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&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...