好吧,我有一些代码似乎可以工作,但我不确定它是否总是能工作。我正在使用类的一个成员作为映射键将unique_ptr移动到stl映射中,但我不确定在某些情况下移动是否会使指针无效。
代码如下:
struct a
{
std::string s;
};
std::map<std::string, std::unique_ptr<a>> m;
std::unique_ptr<a> p = std::make_unique<a>();
// some code that does stuff
m[p->s] = std::move(p);
因此,目前这似乎有效,但在我看来,在字符串用作映射键之前,p可能会变得无效,这将导致内存异常。显然,我可以在移动之前创建一个临时字符串,也可以通过迭代器进行分配,但如果没有必要,我宁愿不这样做。
此代码具有定义良好的行为。
在C++17中,std::move(p)
将在m[p->s]
之前进行评估。在C++17之前,std::move(p)
可以在m[p->s]
之前或之后进行评估。但是,这并不重要,因为std::move(p)
不会修改p
。实际导致p
从中移出的只是分配。
被调用的赋值运算符具有签名
unique_ptr& operator=(unique_ptr&& other);
并且被调用
m[p->s].operator=(std::move(p));
这意味着,在进入operator=
的主体之前,保证不会对p
进行修改(other
参数的初始化仅为引用绑定(。当然,在评估对象表达式m[p->s]
之前不能输入operator=
的主体。
因此,您的代码在所有版本的C++中都是定义良好的。
代码很好。在C++17中,我们在排序上得到了强有力的保证,这使得这个代码100%可以
在C++17之前,标准具有
在所有情况下,赋值都是在右操作数和左操作数的值计算之后,赋值表达式的值计算之前进行的。
但这仍然意味着代码是可以的。我们不知道m[p->s]
和std::move(p)
中的哪一个先发生,但由于move
实际上对p
没有任何作用,因此p->s
将是有效的,并在p
移动到m[p->s]
之前得到解决