std::optional
кажется отличным способом сделать это, если вы используете C ++ 17.
#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