Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 转发返回值。是否需要转发?_C++_C++11_Return_Rvalue Reference_Perfect Forwarding - Fatal编程技术网

C++ 转发返回值。是否需要转发?

C++ 转发返回值。是否需要转发?,c++,c++11,return,rvalue-reference,perfect-forwarding,C++,C++11,Return,Rvalue Reference,Perfect Forwarding,我正在编写一个库,它封装了其他库中的许多函数和方法。为了避免返回值的重叠,我正在应用std::forward如下: template<class T> T&& wrapper(T&& t) { f(t); // t passed as lvalue return std::forward<T>(t); } 它不能证明任何原因,因为它是未定义的行为(如果是UB) 不,您不需要使用std::forward最好不要返回r值引

我正在编写一个库,它封装了其他库中的许多函数和方法。为了避免返回值的重叠,我正在应用
std::forward
如下:

template<class T>
T&& wrapper(T&& t) { 
   f(t);  // t passed as lvalue  
   return std::forward<T>(t);
}

它不能证明任何原因,因为它是未定义的行为(如果是UB)

不,您不需要使用
std::forward
最好不要返回r值引用,因为它可以防止NRVO优化。您可以在本文中阅读有关移动语义的更多信息:

根据此函数传递的内容,它会导致未定义的行为!更准确地说,如果将非左值(即右值)传递给此函数,则返回的引用引用的值将过时

此外,
T&&
也不是一个“通用参考”,尽管其效果有点像通用参考,因为
T
可以推断为
T&
T常量&
。有问题的情况是当它被推断为
T
:参数作为临时传入,并在函数返回后但在任何东西都无法获得对它的引用之前消失

std::forward(x)
的使用仅限于在调用另一个函数时转发对象:作为临时值输入的内容看起来像函数中的左值。使用
std::forward(x)
可以让
x
看起来像一个临时变量,如果它是作为一个变量出现的,那么就可以在创建被调用函数的参数时从
x
移动

从函数返回对象时,可能需要注意一些场景,但没有一个场景涉及
std::forward()

  • 如果类型实际上是一个引用,无论是
    const
    还是非
    const
    ,您都不想对对象执行任何操作,只需返回引用即可
  • 如果所有
    return
    语句都使用相同的变量,或者所有语句都使用临时变量,则可以使用copy/move省略,并且将在适当的编译器上使用。由于复制/移动省略是一种优化,因此不一定会发生
  • 如果始终返回相同的局部变量或临时变量,则可以从中移动它(如果存在移动构造函数),否则将复制对象
  • 当返回不同的变量或返回涉及表达式时,仍然可以返回引用,但复制/移动省略将不起作用,如果不是临时的,也不可能直接从结果中移动。在这些情况下,需要使用
    std::move()
    来允许从本地对象移动

在大多数情况下,生成的类型是
T
,您应该返回
T
,而不是
T&
。如果
T
是左值类型,则结果可能不是左值类型,并且可能需要从返回类型中删除引用限定。在本场景中,您特别询问了类型
T
是否有效。

如果您确实知道
T
在调用
f
后不会处于“从”状态,则您有两个合理的选择:

  • 返回
    std::forward(t)
    ,类型为
    t&
    ,避免任何构造,但允许写入,例如
    auto&&ref=wrapper(42)
    ,这会留下一个悬空引用

  • 返回
    std::forward(t)
    ,类型为
    t
    ,在最坏的情况下,当参数为右值时请求移动构造——这避免了上述prvalues问题,但可能会从xvalues中窃取


在所有情况下,您都需要
std::forward
。不考虑复制省略,因为
t
始终是一个引用。

Prvalues可能有问题,并且确实会导致过时的引用,但是xvalues不太可能以UB结尾——我并不认为返回moved from值特别有用。如果将右值传递给此函数,则返回的引用引用的值将过时“.我可能很笨,但为什么呢?如果调用方将右值传递给临时值,那么该临时值是否至少在调用方的完整表达式结束之前存在,因此足够长,可以被该函数的返回值引用?因此类似于
my\u Foo\u vector.emplace\u back(包装器(Foo())
。我看到返回
T
也会允许这样做,我只是看不到返回
T&
时会产生一个过时的引用。从概念上讲,您创建的临时对象不是函数看到的对象!从概念上讲,函数看到的是这个对象的副本。参数的生命周期比wh中的完整表达式早结束ich temporary被创建。特别是,5.2.2[expr.call],第4段包含以下句子:“…参数的生命周期在定义它的函数返回时结束…”在实践中,你会看到这个对象的复制/移动被省略。即使我把这个逻辑搞错了,这个对象在概念上是过时的,因为它在被传递的时候被移动了。事实上,我想我已经把自己弄糊涂了:右值引用仍然是一个引用,也就是说,不应该有任何临时对象的副本,它仍然存在ng足以返回对它的引用。尽管如此,仍然存在一个问题,但问题比我想象的还要严重:在调用
f(std::forward(t))
中,函数
f()
获得从
t
移动对象的权限,并在
wrapper()中引用
t
需要假设
t
已从中移动。如果
f()
未从传递的对象移动,则调用
f()
时无需使用
std::forward()
。好的,慢慢来:对
f()
的调用不应
std::forward(t)
如果
t
的内容不能被窃取,则发送到被调用函数:转发的目的是使内容能够在
auto&& tmp = wrapper(42);