在各种开关情况下初始化变量

时间:2014-10-08 20:35:21

标签: c++ c++11

我需要编写以下代码(在C ++ 11中):

X x;
if( cond ) {
    x = X(foo);
}
else {
    x = X(foo, bar);
}
// ... continue using x

问题是' X x'将调用默认构造函数并创建一个X类型的不需要的对象。

我该如何解决这个问题?我怀疑可能有一些解决方案涉及新的&&操作员,但我不太明白......

3 个答案:

答案 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

请注意,后者要求您最终手动调用析构函数。