#include <iostream>
#include <string>
#include <map>
struct A {
int n { 42 };
std::string s { "ciao" };
};
int main() {
A a;
std::map<std::string, A> m;
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: ciao"
m.emplace(a.s, std::move(a)); // a.s is a member of a, moved in the same line
std::cout << "in map: " << m.count("ciao") << std::endl; // print: "in map: 1"
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: " (as expected, it has been moved)
}
将“移动”对象的成员作为参数传递是否安全?在这种情况下,emplace似乎可以工作:地图具有预期的键。
有趣的。出于种种原因,我认为这是安全的。(出于记录的考虑,我还认为它的样式非常糟糕-明确的副本在这里不会花您任何钱,因为它将被移至地图中。)
首先,实际的函数调用不是问题。std::move
仅强制转换a
为右值引用,而右值引用只是引用;a不会立即移动。emplace_back
将其参数转发给的构造函数std::pair<std::string, A>
,这就是使事情变得有趣的地方。
那么,std::pair
使用的是哪个构造函数?它有很多,但是两个是相关的:
pair(const T1& x, const T2& y);
template<class U, class V> pair(U&& x, U&&y);
(请参阅标准中的20.3.2),其中T1
和T2
是的模板参数std::pair
。根据13.3,我们最终使用U == const T1&
和V == T2
来实现后者,这在直觉上是有意义的(否则std::pair
实际上将不可能进入a )。这给我们留下了以下形式的构造函数
pair(const T1& x, T2 &&y) : first(std::forward(x)), second(std::forward(y)) { }
按照20.3.2(6-8)。
那么,这安全吗?有用的std::pair
是,定义了一些细节,包括内存布局。它特别指出
T1 first;
T2 second;
按此顺序进入,因此first
将在之前初始化second
。这意味着在您的特定情况下,字符串将在移走之前被复制,因此很安全。
但是,如果您反过来这样做:
m.emplace(std::move(A.s), A); // huh?
...然后您会得到有趣的效果。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句