【问题标题】:How can I conditionally instantiate an object?如何有条件地实例化一个对象?
【发布时间】:2020-10-20 03:26:54
【问题描述】:

我正在尝试像这样做一些有条件的工作:

Type object;
if (cond) {
    doSomeStuff();
    object = getObject();
    doMoreStuff();
} else {
    doSomeOtherStuff();
    object = getDifferentObject();
    doEvenMoreStuff();
}
use(object);

我能想到解决这个问题的唯一方法是复制use 代码(实际上是我的应用程序中的内联代码)并在if 块的每个分支中声明object。如果我想避免重复代码,我必须将它包装在一些使用函数中,就像我上面所说的那样。在实际情况下,这个use 函数可能需要 5+ 个参数来实质上继承上下文。这一切看起来都很混乱,而且无法维护。

if (cond) {
    doSomeStuff();
    Type object = getObject();
    doMoreStuff();
    use(object);
} else {
    doSomeOtherStuff();
    Type object = getDifferentObject();
    doEvenMoreStuff();
    use(object);
}

解决这个问题的最佳方法是什么? Type 没有默认构造函数,因此 sn-p 1 无法编译。

其他一些语言支持 sn-p 1 - 相关问题:Forcing uninitialised declaration of member with a default constructor

【问题讨论】:

  • doSomeStuff()doSomeOtherStuff() 的相关性是什么?
  • @idclev463035818 它的代码我已经抽象出来了。
  • 看起来像个骗子:stackoverflow.com/questions/9346477/…
  • 第二个版本(几乎)没有重复代码,这有什么问题?
  • @NathanOliver Type has no default constructor, thus snippet 1 doesn't compile.

标签: c++ class optimization conditional-statements instantiation


【解决方案1】:

把它放在一个函数里面:

Type doStuffAndCreateType() {
    doSomeStuff();
    Type object = getObject();
    doMoreStuff();
    return object;
}

Type doOtherStuffAndCreateType() {
    doSomeOtherStuff();
    Type object = getObject();
    doEvenMoreStuff();
    return object;
}

Type object = cond ? doStuffAndCreateType() : doOtherStuffAndCreateType();
use( object );

【讨论】:

  • 或者:Type object = cond ? doStuffAndCreateType() : doOtherStuffAndCreateType(); 不需要第三个函数。
  • @RemyLebeau 同意
【解决方案2】:

看看std::optional:

#include <optional>

std::optional<Type> object;
if (cond) {
    doSomeStuff();
    object = getObject();
    doMoreStuff();
} else {
    doSomeOtherStuff();
    object = getDifferentObject();
    doEvenMoreStuff();
}
use(object.value());

【讨论】:

  • 我这样说是因为我实际上使用的是共享系统内存,并且使用了“新放置”,所以这真的不可用 - 或可取
  • @TobiAkinyemi:这不会进行任何堆分配。 std::optional 在内部使用放置新。如果您已经手动进行了新的放置,那么......就这样做
【解决方案3】:

您可以使用 IIILE(立即调用初始化 lambda 表达式):

auto object = [&] {
  if (cond) {
    doSomeStuff();
    auto object = getObject();
    doMoreStuff();
    return object;
  } else {
    doSomeOtherStuff();
    auto object = getDifferentObject();
    doEvenMoreStuff();
    return object;
  }
}();  // note that the lambda must be called

use(object);

即使Type 不是默认可构造的,这也会起作用。

这是demo

【讨论】:

  • 假设 NVRO,returns 不应调用任何移动构造函数,但仍需要存在一个。为了避免这种情况,(仅在必要时才这样做:即Type 是不可移动的),return 从lambda 直接 初始化prvalue,然后分别处理“after”代码。
  • @HTNW 我不确定我是否遵循。有了 NRVO,这还不够吗?
  • @HTNW 这不应该改变任何东西,因为保证复制省略。如果编译器无法执行 NRVO,您将采取行动,但您无能为力。
  • 那么,auto 没有必要吗?
  • @TobiAkinyemi 您可以在所有三个位置都写Type 而不是auto,但这不会改变您获得的副本数量。如果您的编译器不够聪明(无法执行 NRVO),这种方法可能会给您额外的移动(而不是复制),否则您将一无所获。在这两种情况下都不会复制object
猜你喜欢
  • 1970-01-01
  • 2019-10-01
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 1970-01-01
相关资源
最近更新 更多