我基本上会编写以下代码。我明白为什么它不能编译。
A instance; // A is a non-default-constructable type and therefore can't be allocated like this
if (something)
{
instance = A("foo"); // use a constructor X
}
else
{
instance = A(42); // use *another* constructor Y
}
instance.do_something();
有没有办法实现这种行为没有涉及堆分配?
答案 0 :(得分:10)
有更好,更清晰的方法来解决问题,而不是在堆栈上显式保留空间,例如使用条件表达式。
但是,如果类型不是可构造的,或者你有更复杂的条件意味着真的确实需要在堆栈上保留空间以便稍后在两个不同的地方构建某些东西,你可以使用解决方案如下。
标准库提供aligned_storage
特征,因此aligned_storage<T>::type
是正确大小的POD类型和用于存储T
的对齐方式,因此您可以使用它来保留空间,然后使用placement-new将对象构造到该缓冲区中:
std::aligned_storage<A>::type buf;
A* ptr;
if (cond)
{
// ...
ptr = ::new (&buf) A("foo");
}
else
{
// ...
ptr = ::new (&buf) A(42);
}
A& instance = *ptr;
请记住手动销毁它,您可以使用unique_ptr
和自定义删除器进行销毁:
struct destroy_A {
void operator()(A* a) const { a->~A(); }
};
std::unique_ptr<A, destroy_A> cleanup(ptr);
或者使用lambda,虽然这会浪费堆栈上的额外指针; - )
std::unique_ptr<A, void(*)(A*)> cleanup(ptr, [](A* a){ a->~A();});
甚至只是一个专用的本地类型,而不是unique_ptr
struct Cleanup {
A* a;
~Cleanup() { a->~A(); }
} cleanup = { ptr };
答案 1 :(得分:8)
假设您想多次执行此操作,可以使用辅助函数:
A do_stuff(bool flg)
{
return flg ? A("foo") : A(42);
}
然后
A instance = do_stuff(something);
否则,您可以使用条件运算符表达式 * :
进行初始化A instance = something ? A("foo") : A(42);
*这是条件运算符“不像if-else
”的示例。
答案 2 :(得分:3)
在某些简单的情况下,您可以使用这种标准的C ++语法:
A instance=something ? A("foo"):A(42);
您没有指定您正在使用的编译器,但在更复杂的情况下,使用gcc
特定于编译器的扩展可以实现这一点:
A instance=({
something ? A("foo"):A(42);
});
答案 3 :(得分:2)
这是一项新职位的工作,但如果您重新审视自己的要求,几乎可以肯定会采用更简单的解决方案。
#include <iostream>
struct A
{
A(const std::string& str) : str(str), num(-1) {};
A(const int num) : str(""), num(num) {};
void do_something()
{
std::cout << str << ' ' << num << '\n';
}
const std::string str;
const int num;
};
const bool something = true; // change to false to see alternative behaviour
int main()
{
char storage[sizeof(A)];
A* instance = 0;
if (something)
instance = new (storage) A("foo");
else
instance = new (storage) A(42);
instance->do_something();
instance->~A();
}
通过这种方式,您可以随时构建A
,但存储仍然在堆栈中。
但是,你必须自己破坏对象(如上所述),这是令人讨厌的。
免责声明:我的弱放置 - 新示例是天真的,不是特别便携。 GCC自己的Jonathan Wakely发布了一个更好的例子。
答案 4 :(得分:2)