【问题标题】:How to make a rValue reference available outside the try-block in which the RR obtains its value?如何使 rValue 引用在 RR 获取其值的 try 块之外可用?
【发布时间】:2014-10-04 09:07:11
【问题描述】:

假设我们不想重新设计函数a_func_that_may_throw

try {
    T&& rr = a_func_that_may_throw();
}
catch (const std::exception& e) {
    /* Deal with the exception here. */
}
// Question: How to adapt the code above so as to have `rr` available here?

抱歉,我的问题没有问清楚。添加以下内容以(希望)使问题更清晰。

我们可以对指针这样做:

T *ptr = nullptr;
try {
    ptr = a_source_that_may_throw();
}
catch (const std::exception& e) {
    /* We know what happened in the try block and can do something without `ptr`. */
}
// `ptr` is available out side the try block.

自 C++11 起,我们的工具架上就有了 rValue 引用,这使我们免于低效复制现有(可能设计不良)函数返回的巨大对象。是不是可以同时享受这两种优势,这样我们就不用复制了,仍然可以像上面代码中使用ptr一样访问返回的对象?

谢谢。 m(_ _)m

【问题讨论】:

  • 如果该函数确实抛出,rr 未定义。为什么您希望能够引用它?
  • 其他方式:将需要引用的所有内容移入 try 块。
  • 如果函数抛出异常,我们当然会知道,我们可以在 catch-block 中优雅地结束进程。
  • @Mat OP 不会尝试在抛出时引用它,如果它没有抛出,他会尝试引用它。
  • @Cody:不是一切,只是需要参考的一切。如果这太大而无法解释,请重构您的代码。

标签: c++ c++11 exception-handling move-semantics rvalue-reference


【解决方案1】:

如果您使用 r 值引用的原因是您希望将 non const 引用绑定到临时变量,那么恕我直言,根本不用打扰。而是使用值语义并让编译器进行优化。

T t;
try {
    t = a_func_that_may_throw(); // Compiler can use RVO and move assign to 't'.
} catch (const std::exception& e) {
    /* Deal with the exception here. */
}
// 't' has lifetime until end of scope.

如果T 不是默认可构造或不可移动分配,则例外。

也可以按照 cmets 中 @Kerrek SB 的说明进行操作,即将所有内容移入 try 块中。

【讨论】:

  • 我宁愿把它放到一个 lambda/函数中以从 RVO 中受益:T t = []{ try { return a_function_that_may_throw(); } catch(...) { /* ... */ } } ();
  • @dyp 很有趣,但是如果函数抛出,会发生什么?以后访问t 不是一个可能的UB,因为lambda 什么都不返回(除非你从catch 块返回一些东西)?
  • 是的,您必须在catch(或之后)中抛出或返回某些内容。另一种方法是返回boost::optional<T>
【解决方案2】:

这取决于您所说的“处理异常”是什么意思。你可以这样做:

T wrap_a_func_that_may_throw() {
  try {
    return a_func_that_may_throw();
  } catch(const std::exception& e) {
    // Do cleanup, logging, etc...
    // May have to re-throw if there is
    // nothing meaningful you can return.... 
  }
  return T()  // Return empty T if possible.
}

Foo&& foo = wrap_a_func_that_may_throw();

这使您有机会进行任何特定的清理、日志记录等,但可能需要重新抛出。正如 Kerrek SB 所说,您可能仍然需要在 try 块中包含使用引用的所有内容。

【讨论】:

  • 如果a_func_that_may_throw 按值返回,您将遇到终身问题。
  • @dyp 出于某种原因,我假设 a_func_that_may_throw 按 r-value ref 返回,但您的值是正确的可能性更大。
猜你喜欢
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多