【问题标题】:How to move from std::optional<T>如何从 std::optional<T> 移动
【发布时间】:2013-07-04 08:44:44
【问题描述】:

考虑以下示例,我们解析数据并将结果传递给下一个函数:

Content Parse(const std::string& data);
void Process(Content content);

int main()
{
    auto data = ReadData();
    Process(Parse(data));    
}

现在让我们使用std::optional 更改代码来处理失败的解析步骤:

optional<Content> Parse(const std::string& data);
void Process(Content content);

int main()
{
    auto data = ReadData();
    auto content = Parse(data);
    if (content)
        Process(move(*content));
}

optional&lt;T&gt;::value() 迁移是否有效?如果std::optional 可以,那么boost::optional 也可以吗?

【问题讨论】:

  • 我认为这会很好。包含的值在移动后应该处于有效但未指定的状态。

标签: c++ std c++14 boost-optional


【解决方案1】:

optional&lt;T&gt;::value() 移动是有效的,因为它返回一个可变引用并且移动不会破坏对象。如果optional 实例未参与value() 将引发bad_optional_access 异常(第 20.6.4.5 节)。

您明确检查该选项是否已启用:

if (content)
    Process(move(*content));

但您不使用成员value() 访问底层T。请注意,value() 在返回有效的T&amp; 之前会在内部执行检查,这与operator* 不同,operator* 有一个 先决条件,即应使用optional 实例。这是一个微妙的区别,但你使用正确的成语:

if (o)
  f(*o)

相对

if (o)  // redundant check
  f(o.value())

在 Boost 中,情况略有不同:首先,不存在名为 value() 的成员函数来提供检查访问。 (bad_optional_access 异常根本不存在)。成员 get() 只是 operator* 的别名,并且始终依赖于用户检查 optional 实例是否已启用。

【讨论】:

  • operator* 是否有右值引用过载?即f( *std::move(o) )——这会动吗?我希望如此!
  • 我在the standard 中找不到。请查看第 505 页的 §20.6.4 中的接口描述。
  • 嗯。 value_or 具有 &amp;&amp;&amp; 过载。 value 没有(为什么不呢?天真地,它应该)。我可以看到不想要&amp;&amp; operator* 以防人们在不检查optional 是否首先参与的情况下被诱惑*,但是投掷value 我看不到伤害吗?
  • 查看更新的 C++17 标准草案 (open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf) 和 && 观察者已经在那里。请参见第 557 页。
【解决方案2】:

对于您当前的实施,答案是否定的。但是,如果您稍微更改它,您将能够移动该值。可选的运算符 * 有 4 个重载(以及方法 value())。其中只有 2 个将右值引用(_Ty &&const _Ty &&)返回到封装值。但它们分别具有签名 &&const &&。这意味着只有当您的可选变量本身通过右值引用访问时,您才能使用它们。在这种情况下,实现应该如下所示:

std::optional<Content> Parse(const std::string& data);
void Process(Content content);

int main()
{
    auto data = ReadData();
    auto content = Parse(data);
    if (content)
        Process(*std::move(content));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-14
    • 2014-06-24
    • 1970-01-01
    • 2012-06-21
    • 2018-02-02
    • 2018-02-10
    • 2021-08-26
    • 1970-01-01
    相关资源
    最近更新 更多