如何在堆栈上为非默认构造对象保留空间
How do I reserve space on the stack for a non-default constructible?
我基本上会编写以下代码。我理解为什么它不能编译。
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();
有没有一种方法可以在不涉及堆分配的情况下实现这种行为?
有比在堆栈上显式保留空间更好、更干净的方法来解决问题,例如使用条件表达式。
但是,如果类型不可移动构造,或者您有更复杂的条件,这意味着确实需要在堆栈上保留空间,以便稍后在两个不同的地方构造一些东西,您可以使用下面的解决方案。
标准库提供了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 };
假设您想多次执行此操作,则可以使用辅助函数:
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
"的例子
在一些简单的情况下,您可以使用以下标准C++语法:
A instance=something ? A("foo"):A(42);
您没有指定要使用的编译器,但在更复杂的情况下,使用gcc
编译器特定的扩展是可行的
A instance=({
something ? A("foo"):A(42);
});
这是一项新职位的工作,尽管如果您重新审视您的需求,几乎可以肯定会有更简单的解决方案。
#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发布了一个更好的例子来说明同样的想法。
std::experimental::optional<Foo> foo;
if (condition){
foo.emplace(arg1,arg2);
}else{
foo.emplace(zzz);
}
则使用CCD_ 9进行访问。boost::optional
(如果您没有C++1z TS实现),或者编写自己的optional
。
在内部,它将使用类似std对齐的存储和bool
来保护"我已经创建了吗";或者可能是CCD_ 13。编译器可能会证明不需要bool
,但我对此表示怀疑
实现可以从github下载,也可以使用boost。
- 保留计时器集合(对象与指针)的最佳方法
- 更改保留指向其字段的原始指针的对象地址
- 保留对象成员变量的本地副本
- 如何为同一类对象的成员函数保留单独的变量副本?
- 有没有办法在对象上保留弱引用并控制其生存期
- 在C 中进行可选参考,保留对象寿命
- C++对象保留?
- 是否应将移出对象保留为"safe"状态?
- 返回类型,或如何保留对象指针的类型
- 如何获得一个窗口,以便在调整C++大小时保留绘制的对象
- 实例变量列表中的对象未被保留?指针问题
- 保留一个reference_wrapper对象的向量,这是可能的
- 每次创建一个新对象或保留一个对象
- 如何在堆栈上为非默认构造对象保留空间
- 将临时对象保留在寄存器上以避免虚拟机中的额外存储/加载
- std::vector 不保留在实现中实例化的推回对象
- 如何保留指向插入到集合中然后推送到向量中的对象的指针
- 如何在不复制和保留 std::string 对象的情况下获得 C++ std::string 字符数据的所有权
- C++对象中保留 lambda 表达式
- 在c++ 11中,如何调用new并为对象保留足够的内存?