将std :: forward_as_tuple()结果传递给可能从该对象的rvalue-reference成员移动的多个函数?

时间:2012-01-13 04:02:55

标签: c++ c++11 rvalue-reference temporary lifetime

编辑:我认为我所询问的最有可能的用例是创建一个从std::forward_as_tuple()接收rvalue-references元组的函数。

这个问题浮现在脑海中的原因是因为我正在检查传递给构造函数初始值设定项的对象的成员以查看它们是否是rvalue-references(我很乐意告诉我这是错误的错误...希望将来遵循一个经验法则来避免这种情况,但这就是提出问题的原因)。在我看来,在一个稍微不同的上下文中,我可能最终将具有rvalue-reference成员的对象交给多个函数(或函数对象),我可能控制也可能不控制,这可能会从这些成员移动。

template<typename... Args>
void my_func(std::tuple<Args...>&& tup) {

    //if tup's members are rvalue references,
    //and this function moves guts from tup members, then...
    func_i_dont_control(tup); 

    //what happens here if moves are done on the same members?
    another_func_i_dont_control(std::move(tup));
}

我看过Use of rvalue reference members?,以及其他一些关于右值参考成员的讨论,但我无法明确地对此进行排序。

我不只是询问会发生什么,而是这个场景是否应该/甚至可能发生,以及在传递包含rvalue-reference成员的对象时要记住哪些关键规则。

2 个答案:

答案 0 :(得分:1)

元组和可变参数模板的使用似乎减损了问题的重点,所以让我重新说一下:

void func(std::unique_ptr<Foo>&& foo) {
  std::unique_ptr<Foo> bar1(std::move(foo));
  std::unique_ptr<Foo> bar2(std::move(foo));
}

这里发生了什么?好吧,bar2始终包含空指针(bar1可能,具体取决于foo的原始值。)

没有未定义的行为,因为移动构造函数应该使对象处于可用状态 citation needed ,正是出于安全原因。所以你可以使用移动的对象,但是它的状态可能不是很有趣:它甚至不需要等同于默认的构造状态,它只能是陈旧状态。

答案 1 :(得分:1)

在此代码func_i_dont_control中无法以静默方式窃取参数。只有rvalues绑定到rvalue引用,而命名变量不是rvalue。您的代码无法编译,或func_i_dont_control(有重载)不使用移动语义。

要让func_i_dont_control有机会窃取元组(将元组绑定到右值引用),必须使用std::move(tup)将其显式转换为右值。

(一个带左值参考的函数不应该从它移开,否则我们真的不知道会发生什么。)


编辑但问题似乎不是关于元组本身,而是其成员。同样,这些成员不会是rvalues,因此func_i_dont_control需要明确地移动它们。我不认为它有“道德权利”*这样做,除非它将整个元组作为右值接收,这在你的函数中没有发生。

*使用移动语义,您必须遵循某些准则。基本上你可以向rvalue投射任何东西并从中移动,如果你正在处理左值或右值引用并不重要。只要遵循这些准则,移动语义就能正常工作。如果你开始将事物投射到rvalues而不考虑那些准则,那么在函数调用之后对象将开始消失。