我需要编写以下代码(在C ++ 11中):
X x;
if( cond ) {
x = X(foo);
}
else {
x = X(foo, bar);
}
// ... continue using x
问题是' X x'将调用默认构造函数并创建一个X类型的不需要的对象。
我该如何解决这个问题?我怀疑可能有一些解决方案涉及新的&&操作员,但我不太明白......
答案 0 :(得分:5)
使用它来避免任何临时措施:
auto&& x = cond ? X(foo) : X(foo, bar);
如果初始化更复杂,请使用lambda:
auto&& x = [&]()->X{
if(cond1)
return {};
if(cond2)
return {foo};
return {foo, bar};
}();
使用通用引用,并且lambda通过引用获取,以避免无用的副本。
还使用了list-initialization而没有未命名的临时值,因此lambda的返回不会发生复制。
请注意list-initialization-syntax有利于ctor期待初始化列表 在这种情况下,你必须依赖RVO。
答案 1 :(得分:3)
如果案件数量相当小,请使用条件运算符:
auto&& x = cond? X(foo) : X(foo, bar);
或者是lambda:
auto&& x = [=] // choose default-capture appropriately.
{
if (cond) {
return X(foo);
}
else {
return X(foo, bar);
}
}();
在这两种情况下,复制省略都有助于消除任何可能的移动或副本,因此作为x
的类型的引用并非真正必要。
您还可以在return
语句中使用列表初始化来避免任何移动或副本(尽管这不会产生某些类的等效行为,请尝试一下):
auto&& x = [=]() -> X // Note the trailing return type.
{
if (cond) {
return {foo};
}
else {
return {foo, bar};
}
}();
答案 2 :(得分:1)
我说最简单的就是使用Boost.Optional:
#include "boost/optional.hpp"
boost::optional<X> x;
if (cond) {
x = X(foo);
} else {
x = X(foo, bar);
}
// ... continue using *x where you would have used x
或者,如果您不想/不能使用Boost,并且您知道每个分支都会执行初始化,您可以使用std::aligned_storage
和新位置:
std::aligned_storage<X> xStorage;
X *x;
if (cond) {
x = new (&xStorage) X(foo);
} else {
x = new (&xStorage) X(foo, bar);
}
// ... continue using *x where you would have used x
请注意,后者要求您最终手动调用析构函数。