c – 作为参数传递正在移动的对象的成员是否安全

前端之家收集整理的这篇文章主要介绍了c – 作为参数传递正在移动的对象的成员是否安全前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
#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转换为rvalue引用,而rvalue引用只是引用; 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(const T1& x,T2 &&y) : first(std::forward(x)),second(std::forward(y)) { }

按照20.3.2(6-8).

那么,这样安全吗?有用的是,std :: pair的定义有些细节,包括内存布局.特别是,它说明了这一点

T1 first;
T2 second;

按顺序排列,所以首先在第二个之前初始化.这意味着在您的特定情况下,字符串将在移走之前被复制,并且您是安全的.

但是,如果你这样做,反过来说:

m.emplace(std::move(A.s),A); // huh?

…然后你会得到有趣的效果.

猜你在找的C&C++相关文章