std::vector、不完整类型和继承的构造函数

isa*_*nae 7 c++ inheritance destructor

vector我有一个带有成员变量的类T,该变量已声明但未定义。如果没有定义该类的析构函数,这可能会出现问题,因为编译器可能会选择其他一些翻译单元来生成析构函数。如果该 TU 没有 的定义,则T编译会失败。

struct undefined;

struct S
{
    S(int);
    std::vector<undefined> v;
};

int main()
{
   S s(42);     // fails in ~vector(), `undefined` is undefined
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我通常在实现该类的文件中添加一个默认的析构函数作为锚点,该类可以访问该定义。

struct undefined;

struct S
{
    S(int);
    ~S();       // implemented in another TU as `S::~S() = default;`
    std::vector<undefined> v;
};

int main()
{
   S s(42);     // ok
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试对继承基类构造函数的派生类执行相同的操作:

#include <vector>

struct undefined;

struct base
{
   base(int);
};

struct derived : base
{
   using base::base;
   ~derived();
   std::vector<undefined> v;
};


int main()
{
   derived d(1);  // fails in ~vector(), `undefined` is undefined
}
Run Code Online (Sandbox Code Playgroud)

如果我更改derived为不继承构造函数,则编译成功:

#include <vector>

struct undefined;

struct base
{
   base(int);
};

struct derived : base
{
   //using base::base;           <--- note
   derived(int);
   ~derived();
   std::vector<undefined> v;
};


int main()
{
   derived d(1);  // ok
}
Run Code Online (Sandbox Code Playgroud)

真正让我困惑的是 clang 是这么说的:

stl_vector.h:336:35: error: arithmetic on a pointer to an incomplete type 'undefined'

[blah]

a.cpp:12:14: note: in instantiation of member function 'std::vector<undefined>::~vector' requested here
        using base::base;
                    ^
Run Code Online (Sandbox Code Playgroud)

听起来好像using base::base也带来了一些破坏的东西vector,但我不知道是什么。我尝试删除两个类中的复制/移动构造函数/运算符,但错误仍然存​​在。g++ 和 Visual C++ 都会失败并出现类似的错误。

这是怎么回事?

isa*_*nae 0

正如Raymond Chen在此评论中提到的,之所以using base::base需要vector析构函数,是因为构造函数可能会抛出异常,这可能需要销毁成员变量。唯一的解决方案是手动编写构造函数。

如果抛出异常,构造函数需要销毁完全构造的成员变量。在此示例中,a必须被销毁,但不能b

std::string throws()
{
    throw 1;
}

struct S
{
    std::string a, b;

    S() : a(""), b(throws()) {}
};
Run Code Online (Sandbox Code Playgroud)

在下一个示例中,编译器生成默认构造函数和析构函数。两者都可以调用~vector(),因此都需要定义incomplete

struct incomplete;

struct S
{
    std::vector<incomplete> v;
};

int main()
{
    S s;  // error
}
Run Code Online (Sandbox Code Playgroud)

为两者添加声明可以修复错误:

struct incomplete;

struct S
{
    std::vector<incomplete> v;
    S();
    ~S();
};

int main()
{
    S s;   // ok
}
Run Code Online (Sandbox Code Playgroud)

但是继承的构造函数也是由编译器生成的,因此需要~vector()在抛出异常的情况下使用:

struct undefined;

struct base
{
    base(int);
};

struct derived : base
{
    std::vector<undefined> v;

    using base::base;   // <- needs ~vector() in case of exceptions
    ~derived();
};
Run Code Online (Sandbox Code Playgroud)

因此唯一的解决方案是手动声明构造函数并在其他地方实现它。