【问题标题】:Undefined reference to a destructor in clang未定义的对clang中的析构函数的引用
【发布时间】:2020-02-08 21:03:57
【问题描述】:

编译以下代码会给出“未定义的对 `A::~A() 的引用”:

#include <cstdlib>
#include <memory>

template <typename T>
struct A {
        A() {}
        ~A() {}
};

struct Aggregate {
        using key_vector = A<char>;
        using value_vector = A<int>;

        value_vector vals;
        key_vector keys;
};

int
main()
{
        auto x = malloc(sizeof(Aggregate));
        new (x) Aggregate{};

        return 0;
}

问题出现在 clang 7.0 和 6.0(可能还有一些旧版本)。见:https://godbolt.org/z/GNPk3V

在较新的 clang 版本和 gcc 上它工作正常。

这是预期的还是clang中的某种错误?

【问题讨论】:

  • 如果它有帮助,两个独立的东西分别消除了错误:使用一些 -O 级别编译;并在从main 返回之前插入((Aggregate*)x)-&gt;~Aggregate();。不要问我为什么他们中的任何一个都有效。
  • = default析构函数。或将其全部删除,因为它是空的。我不知道为什么会发生这种情况,但它不应该出现在调用析构函数并删除内存的实际代码中。
  • ~A() = 默认;
  • 如果它不再发生,那么我会认为这是一个已修复的错误。

标签: c++ linker compiler-construction clang


【解决方案1】:

这似乎是Bug 28280,由https://reviews.llvm.org/D45898 修复:

如果花括号初始化列表中的初始化程序是具有非平凡析构函数的 C++ 类,则将析构函数标记为已引用。这修复了 CodeGenFunction::destroyCXXObject 在尝试在堆栈展开路径上发出对析构函数的调用但该类的 CXXRecordDecl 没有析构函数的 CXXDestructorDecl 时发生的崩溃。

这个例子确实使用了一个花括号初始化列表,并在调用 _Unwind_Resume 之前发出了析构函数调用。析构函数不是微不足道的。将初始化更改为使用 () 而不是 {} 会使错误消失,因为它不再使用花括号初始化列表进行初始化。我评论中的析构函数调用可能会导致析构函数被标记为引用。也许启用优化与使优化只出现在非平凡的析构函数中的事情相同。

【讨论】:

    猜你喜欢
    • 2011-12-14
    • 1970-01-01
    • 2020-02-10
    • 2013-08-20
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2015-10-12
    相关资源
    最近更新 更多