首先,我意识到这种事情是玩火,诱惑UB。我要求更好地理解union的角落案例。
据我所知,如果我有一个具有c‘’tor和d‘’tor的类,并将其放入一个union中,编译器将迫使我告诉它如何处理构造和破坏。如图所示
#include <iostream>
struct S {
int x;
S() : x(-1) { std::cout << "S()" << std::endl; }
~S() { std::cout << "~S()" << std::endl; }
static S& instance() {
union DoNotDestruct {
S value;
DoNotDestruct() : value() {}
~DoNotDestruct() {}
};
static DoNotDestruct inst;
return inst.value;
}
};
int main() {
return S::instance().x;
}报告的只是建筑而不是破坏。
但是,如果我有一个删除的析构函数,那就不起作用了;我必须使用Place-new。
#include <new>
// Placement-new version:
struct S0 {
S0() {}
~S0() = delete;
static S0& instance() {
union DoNotDestruct {
S0 value;
DoNotDestruct() {
// I believe value isn't constructed yet.
new (&value) S0; // Placement-new.
}
~DoNotDestruct() {} // Omit S0's d'tor.
};
static DoNotDestruct inst;
return inst.value;
}
};
// Init version:
struct S1 {
S1() {}
~S1() = delete;
static S1& instance() {
union DoNotDestruct {
S1 value;
DoNotDestruct() : value{} {} // Why does this line want S1::~S1() to exist?
~DoNotDestruct() {} // Omit S1's d'tor.
};
static DoNotDestruct inst;
return inst.value;
}
};https://godbolt.org/z/7r4ebszor
在这里,S0很高兴,但是S1在构造函数行上抱怨S1::~S1()被删除了。为什么?
我尝试添加noexcept,因为在class中,如果您有多个成员,那么如果后续的c‘’tors抛出,第0成员需要是可销毁的。看起来,即使是具有已删除的d‘’tor的类本身也不能保存一个不可摧毁的成员,即使c‘函数都是noexcept。它给出了与union:https://godbolt.org/z/jx3W1YEPf相同的错误
发布于 2022-01-19 17:47:09
[class.dtor]/15说,如果可能调用的析构函数被定义为已删除,则程序的格式是错误的。
[class.base.init]/12说,类的潜在构造子对象的析构函数可能在非委托构造函数中被调用。
[特殊]/7说,所有非静态数据成员都有潜在的次对象构造,尽管这个句子有点奇怪,我认为(“对于一个类,.”)。
对于单成员类、联合类或noexcept,我不认为有任何例外。所以在我看来GCC对S1是正确的。
Clang也是Clang、GCC、ICC和MSVC中唯一不拒绝这个版本的编译器。
然而,对于S0来说,这一推理也适用,这也使得它的格式不正确。然而,四个编译器中没有一个同意这一点,所以我可能错了。
引用的措辞大多来自CWG第1424期。Clang和GCC (https://gcc.gnu.org/projects/cxx-dr-status.html)一样,将其目前的实施状况列为未知数(https://gcc.gnu.org/projects/cxx-dr-status.html)。
https://stackoverflow.com/questions/70774468
复制相似问题