这段 C++ 代码会一直按我的预期工作,还是不能保证执行顺序?

Bil*_*ers 5 c++ order-of-execution

好的,我有一些似乎有效的代码,但我不确定它是否总是有效。我正在使用类的一个成员作为映射键将 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);
Run Code Online (Sandbox Code Playgroud)

所以这目前似乎有效,但在我看来,在将字符串用作映射键之前 p 可能变得无效,这将导致内存异常。显然我可以在移动之前创建一个临时字符串,或者我可以通过迭代器进行分配,但如果没有必要,我宁愿不要。

Bri*_*ian 13

此代码具有明确定义的行为。

在 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);
Run Code Online (Sandbox Code Playgroud)

并被称为

m[p->s].operator=(std::move(p));
Run Code Online (Sandbox Code Playgroud)

这意味着p保证在进入of主体之前不会发生对of的修改operator=other参数的初始化只是一个引用绑定)。当然,在评估operator=对象表达式之前,不能进入主体m[p->s]

因此,您的代码在所有版本的 C++ 中都得到了明确定义。


Nat*_*ica 5

代码没问题。在 C++ 17 中,我们在排序方面得到了强有力的保证,这使得这段代码 100% 正确。

在 C++17 之前,标准有

在所有情况下,赋值顺序都在左右操作数的值计算之后,赋值表达式的值计算之前。

但这仍然意味着代码没问题。我们不知道哪个m[p->s]std::move(p)最先发生,但由于move实际上没有对 做任何事情pp->s因此将有效并在p移入之前解决m[p->s]