使用工会来防止破坏?
Using a union to prevent destruction?
相关:How does =delete on destructor prevent stack allocation?
首先,我意识到这种事情是在玩火,诱惑UB。我要求更好地理解 union
s.
的极端情况
据我了解,如果我有一个带有 c'tor 和 d'tor 的 class 并将其放在 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;
}
只报告建造,不报告破坏。
但是,如果我有一个 deleted 析构函数,那似乎不起作用;我必须使用 placement-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'tor 抛出,第 0 个成员需要是可破坏的。看起来即使是删除了 d'tor 的 class 本身也不能拥有坚不可摧的成员,即使 c'tor 都是 noexcept
。它给出与 union
相同的错误:https://godbolt.org/z/jx3W1YEPf
[class.dtor]/15 表示如果 可能调用的 析构函数被定义为已删除,则程序格式错误。
[class.base.init]/12 表示 可能构造的 class 的子对象 的析构函数可能在非委托构造函数中调用。
[special]/7 表示所有非静态数据成员都是潜在构造的子对象,虽然我认为这句话限定有点奇怪(对于 class、[...]").
对于单成员 classes、工会或 noexcept
,我没有看到任何例外情况。所以在我看来 GCC 对于 S1
.
是正确的
Clang 也是 Clang、GCC、ICC 和 MSVC 中唯一不拒绝此版本的编译器。
然而,对于 S0
,此推理也适用,因此它的格式也不正确。然而,四个编译器中的 none 同意这一点,所以也许我错了。
引用的措辞主要来自CWG issue 1424. Clang lists its implementation status currently as unknown (https://clang.llvm.org/cxx_dr_status.html), as does GCC (https://gcc.gnu.org/projects/cxx-dr-status.html)。
相关:How does =delete on destructor prevent stack allocation?
首先,我意识到这种事情是在玩火,诱惑UB。我要求更好地理解 union
s.
据我了解,如果我有一个带有 c'tor 和 d'tor 的 class 并将其放在 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;
}
只报告建造,不报告破坏。
但是,如果我有一个 deleted 析构函数,那似乎不起作用;我必须使用 placement-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'tor 抛出,第 0 个成员需要是可破坏的。看起来即使是删除了 d'tor 的 class 本身也不能拥有坚不可摧的成员,即使 c'tor 都是 noexcept
。它给出与 union
相同的错误:https://godbolt.org/z/jx3W1YEPf
[class.dtor]/15 表示如果 可能调用的 析构函数被定义为已删除,则程序格式错误。
[class.base.init]/12 表示 可能构造的 class 的子对象 的析构函数可能在非委托构造函数中调用。
[special]/7 表示所有非静态数据成员都是潜在构造的子对象,虽然我认为这句话限定有点奇怪(对于 class、[...]").
对于单成员 classes、工会或 noexcept
,我没有看到任何例外情况。所以在我看来 GCC 对于 S1
.
Clang 也是 Clang、GCC、ICC 和 MSVC 中唯一不拒绝此版本的编译器。
然而,对于 S0
,此推理也适用,因此它的格式也不正确。然而,四个编译器中的 none 同意这一点,所以也许我错了。
引用的措辞主要来自CWG issue 1424. Clang lists its implementation status currently as unknown (https://clang.llvm.org/cxx_dr_status.html), as does GCC (https://gcc.gnu.org/projects/cxx-dr-status.html)。