将 std::forward_as_tuple() 结果传递给可能从该对象的右值引用成员移动的多个函数?
编辑:我认为我所询问的最可能的用例是创建一个从 std::forward_as_tuple()
接收右值引用元组的函数。 strong>
想到这个问题的原因是因为我正在检查传递给构造函数初始值设定项的对象的成员,以查看它们是否是右值引用(我愿意接受建议,告诉我这是错误的错了错了...希望后面有根据经验,避免将来出现这种情况,但这就是引发问题的原因)。我想到,在稍微不同的上下文中,我可能最终会将具有右值引用成员的对象传递给我可能控制或可能不控制的多个函数(或函数对象),这些函数可能会从这些成员进行移动。
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));
}
我查看了 使用右值引用成员?,以及其他一些讨论右值引用成员,但我不太能够明确地解决这个问题。
我不只是问会发生什么,而是问这种情况是否应该/可能发生,以及在传递包含右值引用成员的对象时要记住哪些关键规则。
Edit: I think the most likely use case for what I'm asking about, is when creating a function that receives a tuple of rvalue-references from std::forward_as_tuple()
.
The reason this question came to mind is because I was checking the members of objects passed to constructor initializers to see if they were rvalue-references (I'm open to advice telling me that this is wrong wrong wrong... hopefully followed by a rule of thumb to avoid this in the future, but that's what prompted the question). It occurred to me that, in a slightly different context, I might end up handing an object that has rvalue-reference members to multiple functions (or function objects), that I may or may not control, that may do moves from those members.
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));
}
I've looked at Use of rvalue reference members?, along with some other discussions of rvalue reference members, but I'm not quite able to definitively sort this out.
I'm not just asking what would happen, but whether this scenario should/could even happen at all, and what key rules to keep in mind when passing around objects containing rvalue-reference members.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在此代码中,
func_i_dont_control
无法静默窃取参数。只有右值绑定到右值引用,并且命名变量不是右值。您的代码要么无法编译,要么func_i_dont_control
(具有重载)不使用移动语义。为了让 func_i_dont_control 有机会窃取元组(将元组绑定到右值引用),必须使用 std::move(tup) 将其显式转换为右值>。
(采用左值引用的函数不应从它移开,否则我们真的无法判断会发生什么。)
编辑 但问题似乎不是关于元组本身,而是关于它的成员。同样,这些成员不会是右值,因此 func_i_dont_control 需要显式移动它们。我不认为它有这样做的“道德权利”*,除非它接收整个元组作为右值,而这在您的函数中不会发生。
* 对于移动语义,您必须遵循某些准则。基本上,您可以将任何内容转换为右值并从中移动,无论您处理的是左值还是右值引用都没关系。只要遵循这些准则,移动语义就能正常工作。如果您开始将事物转换为右值而忽略这些准则,则对象将在函数调用等之后开始消失。
In this code
func_i_dont_control
cannot silently steal the parameter. Only rvalues bind to rvalue references and a named variable is not a rvalue. Your code either fails to compile, orfunc_i_dont_control
(has an overload that) doesn't use move semantics.To give
func_i_dont_control
the chance to steal the tuple (to bind the tuple to a rvalue reference), it would have to be explicitly cast to rvalue withstd::move(tup)
.(A function taking a lvalue reference should not move from it, otherwise we really can't tell what would happen.)
Edit But the question doesn't seem to be about the tuple itself but its members. Again, those members won't be rvalues, so
func_i_dont_control
would need to move them explicitly. I don't think it has a "moral right"* to do so, unless it receives the whole tuple as a rvalue, which is not happening in your function.* With move-semantics you have to follow certain guidelines. Basically you can cast anything to rvalue and move from it, it doesn't matter if you are dealing with lvalue or rvalue references. As long as you follow these guidelines, move-semantics will work correctly. If you start casting things to rvalues disregarding those guidelines, objects will start disappearing after function calls etc.
元组和可变参数模板的使用似乎偏离了问题的重点,所以让我重新表述一下:
这里发生了什么?嗯,
bar2
始终包含一个空指针(bar1
也可能包含空指针,具体取决于foo
的原始值)。不存在未定义的行为,因为移动构造函数应该使对象处于可用状态需要引用,正是出于安全原因。因此,您可以使用移出的对象,但是它的状态可能不会很有趣:它甚至不需要等于默认的构造状态,它可以只是一个过时的状态。
The use of tuples and variadic templates seems to detract from the point of the question so let me rephrase it:
What happens here ? Well,
bar2
always contains a null pointer (andbar1
might, depending on the original value offoo
).There is no undefined behavior because a move constructor should leave the object in usable state citation needed, precisely for safety reasons. So you can use an object that was moved from, however its state will probably not be very interesting: it need not even be equivalent to the default constructed state, it can just be a stale state.