从一次DEBUG体会modernCPP

今天写树形dp,用匿名函数出现了极其玄学的报错,modernCPP给我上了一课

note: 'solve()::<lambda(auto:23, int, int)>::~()' is implicitly deleted because the default definition would be ill-formed

1|0源代码

void solve() { int n; std::cin >> n; std::vector<int> edge[n + 1]; std::vector<int> F(n + 1); std::vector<int> ind(n + 1); for (int u, v, i = 0; i < n - 1; i++) { std::cin >> u >> v; edge[u].emplace_back(v); edge[v].emplace_back(u); ind[u]++; ind[v]++; } auto dfs = [&](auto self, int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { self(self, to, x); F[x] += F[to]; } return ; }; dfs(dfs, 1, 0); int q; std::cin >> q; while(q--) { int x, y; std::cin >> x >> y; std::cout << F[x] * F[y] << '\n'; } }

2|0排查

由于报错是析构函数出错,比较难以排查,所以就枚举了所有情况,发现以下几种写法可以通过编译。

  • 声明 function 类型

    std::function<void(int, int)> dfs [&](int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { dfs(to, x); F[x] += F[to]; } return ; };

    从声明类型后就可以通过编译我感觉是编译器在 auto 推断时出了错误,然而却并非如此。

  • 注明捕获对象

    auto dfs = [&ind, &edge, &F](auto self, int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { self(self, to, x); F[x] += F[to]; ` } return ; };

    这里找出了真正的原因,自动捕获到了脏东西

3|0解决

自动捕获到了什么脏东西?

对捕获对象逐一排查后,发现对于邻接表存图的 edge,把大小改成常量或者使用 vector 嵌套后就能通过编译。

这里涉及了 CPP 为了兼容 C 而留下的遗留问题

VLA虽然允许存在,但是modernCPP的接口没有义务再兼容VLA

改成嵌套 vector 后即可通过

void solve() { int n; std::cin >> n; std::vector<std::vector<int>> edge(n + 1, std::vector<int>()); std::vector<int> F(n + 1); std::vector<int> ind(n + 1); for (int u, v, i = 0; i < n - 1; i++) { std::cin >> u >> v; edge[u].emplace_back(v); edge[v].emplace_back(u); ind[u]++; ind[v]++; } auto dfs = [&](auto self, int x, int father) -> void { if (ind[x] == 1 && x != 1) {F[x] = 1; return ;} for (auto& to : edge[x]) if (to != father) { self(self, to, x); F[x] += F[to]; } return ; }; dfs(dfs, 1, 0); int q; std::cin >> q; while(q--) { int x, y; std::cin >> x >> y; std::cout << F[x] * F[y] << '\n'; } }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/18034430.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示