微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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?

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

原文地址:https://www.jb51.cc/c/119450.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐