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

Will this C++ code always work as I expect, or is the execution order not guaranteed?

好的,我有一些代码似乎可以工作,但我不确定它是否会始终有效。我正在使用 class 的成员之一作为映射键将 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 中,,这使得这段代码 100% OK。

C++17 之前的标准有

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

但这仍然意味着代码没问题。我们不知道 m[p->s]std::move(p) 中的哪一个先发生,但是由于 move 实际上没有对 p 做任何事情,所以 p->s 将是有效的并且在 p 移动到 m[p->s]

之前解决

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

在 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));

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

所以你的代码在所有版本的 C++ 中都是明确定义的。