从一次DEBUG体会modernCPP

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

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

源代码

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';
    }
}

排查

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

  • 声明 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 ;
    };
    

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

解决

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

对捕获对象逐一排查后,发现对于邻接表存图的 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';
    }
}
posted @ 2024-02-26 15:26  加固文明幻景  阅读(17)  评论(0编辑  收藏  举报