使用 union 推迟成员变量构造
Use union to defer member variable construction
我想将成员变量的构造推迟到构造函数的主体,我正在尝试使用 union 来执行此操作。到目前为止,它正在实现我想要的,但我想问一下我有什么理由不应该这样做吗?
示例:
#include <iostream>
struct A {
A() {
std::cout << "Construct A" << std::endl;
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
A a;
};
template <typename T>
union U {
char a{};
T buffer;
U() {}
~U() {
buffer.~T();
}
};
struct C {
U<B> u;
C() {
try {
new (&u.buffer) B();
} catch (...) {
}
}
};
编辑:添加示例用法
如果您使用的是 C++17,std::optional
似乎是执行此操作的好方法。
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
std::optional<A> a;
B(bool fail = false) {
try {
a.emplace(fail);
}
catch (std::runtime_error& ex) {
// fall back to a safe construction
std::cout << "Falling back to safe A construction" << std::endl;
a.emplace();
}
}
};
int main() {
{
B b_good; // should be fine
}
{
B B_bad(true); // should catch the exception and fall back
}
}
输出:
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
放弃 std::optional
大小的一个选项是拥有未分配的缓冲区,但(为了类型安全)通过引用访问它。
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
char a_buff_[sizeof(A)];
A& a_;
B(bool fail = false) : a_(*reinterpret_cast<A*>(a_buff_)) {
try {
new (&a_) A(fail);
}
catch (std::runtime_error& ex) {
std::cout << ex.what() << std::endl;
std::cout << "Falling back to safe A construction" << std::endl;
new (&a_) A();
}
}
~B() { a_.~A(); }
B(const B& other) : a_(other.a_) {}
B& operator=(const B& other) {
a_ = other.a_;
}
};
int main() {
{
B b_good; // should be fine
}
{
B b_bad(true); // should catch the exception and fall back
}
}
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
Falling back to safe A construction
Attempting to construct A
Succeeded in constructing A
Destruct A
您不应使用变通方法的原因之一是它没有意义。
在孔构造函数上应用 try-catch 会很好。
struct C {
A a;
C() try {
} catch (...) {
}
};
我想将成员变量的构造推迟到构造函数的主体,我正在尝试使用 union 来执行此操作。到目前为止,它正在实现我想要的,但我想问一下我有什么理由不应该这样做吗?
示例:
#include <iostream>
struct A {
A() {
std::cout << "Construct A" << std::endl;
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
A a;
};
template <typename T>
union U {
char a{};
T buffer;
U() {}
~U() {
buffer.~T();
}
};
struct C {
U<B> u;
C() {
try {
new (&u.buffer) B();
} catch (...) {
}
}
};
编辑:添加示例用法
std::optional
似乎是执行此操作的好方法。
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
std::optional<A> a;
B(bool fail = false) {
try {
a.emplace(fail);
}
catch (std::runtime_error& ex) {
// fall back to a safe construction
std::cout << "Falling back to safe A construction" << std::endl;
a.emplace();
}
}
};
int main() {
{
B b_good; // should be fine
}
{
B B_bad(true); // should catch the exception and fall back
}
}
输出:
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
放弃 std::optional
大小的一个选项是拥有未分配的缓冲区,但(为了类型安全)通过引用访问它。
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
char a_buff_[sizeof(A)];
A& a_;
B(bool fail = false) : a_(*reinterpret_cast<A*>(a_buff_)) {
try {
new (&a_) A(fail);
}
catch (std::runtime_error& ex) {
std::cout << ex.what() << std::endl;
std::cout << "Falling back to safe A construction" << std::endl;
new (&a_) A();
}
}
~B() { a_.~A(); }
B(const B& other) : a_(other.a_) {}
B& operator=(const B& other) {
a_ = other.a_;
}
};
int main() {
{
B b_good; // should be fine
}
{
B b_bad(true); // should catch the exception and fall back
}
}
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
Falling back to safe A construction
Attempting to construct A
Succeeded in constructing A
Destruct A
您不应使用变通方法的原因之一是它没有意义。 在孔构造函数上应用 try-catch 会很好。
struct C {
A a;
C() try {
} catch (...) {
}
};