有几个选项可以让您在保留自动存储的同时执行此操作,您应该使用哪一个取决于 type 的语义Object
。
吊舱
如果您有问题中给出的类型,则可以选择将其简化为 POD 类型;基本上,删除所有用户提供的构造函数并为所有内容提供相同的访问说明符:
struct Object {
int mInt1, mInt2;
};
然后,您的初始化模式可能如下所示(使用Placement new):
Object o; // Default-initialized, a no-op
if (condition)
new (&o) Object {i};
else
new (&o) Object {i, j};
一般类型
一般来说,如果您默认初始化然后分配,您的典型值语义类型将完全正常工作,这要归功于移动语义:
std::vector <foo> v;
if (condition)
v = std::vector <foo> (42);
else
v = std::vector <foo> {bar, baz, quux};
不过,您通常仍会在默认构造函数中工作,因为某些类型的默认构造对象(例如std::vector
)具有明确定义的状态。如果您想避免对任意预定义类型进行这项工作,您可能希望使用std::optional
(在撰写本文时实际上还不是标准的):
std::optional <big_but_flat> b;
if (condition)
b.emplace (i);
else
b.emplace (i, j);
没有std::optional
您可能会反对std::optional
与它相关的过多开销,我将把它留给您和您的测量来决定是否是这种情况。无论如何,我们可以得到我们的行为而不用担心开销——但是如果你没有真正执行你的初始化,鼻恶魔可能会怜悯。我们将使用 aunion
来获得我们想要的:
// At function scope
union store_v {
std::vector <int> v;
store_v () {}
~store_v () { v.~vector <int> (); }
} sv;
if (condition)
new (&sv.v) std::vector <int> (42);
else
new (&sv.v) std::vector <int> {49, 343, 2401};
这可能会得到改善。例如,我们可以将存储设为模板:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
if (condition)
new (&sv.t) std::vector <int> (42);
else
new (&sv.t) std::vector <int> {49, 343, 2401};
我们可以给自己一个参考:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
auto&& v = sv.t; // Deduce const, for what that's worth
if (condition)
new (&v) std::vector <int> (42);
else
new (&v) std::vector <int> {49, 343, 2401};
稍微注意细节以避免名称冲突和处理 C++ 的……有趣的声明语法,我们甚至可以定义几个宏来清理代码(实现留给读者作为练习):
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
DECL_UNINIT (std::vector <int>, v);
if (condition)
INIT (v, (42));
else
INIT (v, {49, 343, 2401});