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

Posted

技术标签:

【中文标题】这个 C++ 代码会一直按我的预期工作,还是不能保证执行顺序?【英文标题】:Will this C++ code always work as I expect, or is the execution order not guaranteed? 【发布时间】:2020-07-15 20:41:47 【问题描述】:

好的,我有一些似乎可以工作的代码,但我不确定它是否总是有效。我正在使用类的成员之一作为映射键将 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 可能会变得无效,这会导致内存异常。显然,我可以在移动之前创建一个临时字符串,或者我可以通过迭代器进行分配,但如果没有必要,我不希望这样做。

【问题讨论】:

【参考方案1】:

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

在 C++17 中,std::move(p) 将在 m[p-&gt;s] 之前计算。在 C++17 之前,std::move(p) 可以在 m[p-&gt;s] 之前或之后计算。但是,这并不重要,因为std::move(p) 不会修改p。只有实际导致 p 被移出的赋值。

被调用的赋值运算符有签名

unique_ptr& operator=(unique_ptr&& other);

并且好像被调用

m[p->s].operator=(std::move(p));

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

所以您的代码在所有版本的 C++ 中都定义良好。

【讨论】:

感谢您解决这个问题。我希望它没问题,因为它比替代品更具可读性。【参考方案2】:

代码很好。在 C++ 17 中,we were given strong guarantees on the sequencing,这使得这段代码 100% OK。

在 C++17 之前的标准有

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

但这仍然意味着代码没问题。我们不知道m[p-&gt;s]std::move(p) 中的哪一个最先发生,但由于move 实际上对p 没有任何作用,所以p-&gt;s 将有效并在p 移动到@ 之前得到解决987654328@

【讨论】:

此引用适用于内置赋值运算符,不是吗? @chris 该特定段落适用于所有类型。 @idclev463035818 是的,std::move 只是一个演员表,所以它对p-&gt;s 发生的事情没有影响。不过,报价中确实包含的是,它保证std::move(p)m[p-&gt;s] 都将在实际分配发生(实际移动)发生之前进行评估 我现在在标准中看到了上下文。似乎 cppreference 将文本理解为其他意思,这让我很感兴趣。

以上是关于这个 C++ 代码会一直按我的预期工作,还是不能保证执行顺序?的主要内容,如果未能解决你的问题,请参考以下文章

限制Python3 urllib请求所花费的时间:超时不能按我的预期运行

Angular 订阅无法按我的预期工作

EZAudio 自定义 AudioStreamBasicDescription 没有按我的预期工作

ComboBox DataSource 没有按我预期的那样工作[重复]

文本对齐在 fabric.js 中没有按预期工作

All 子句核心数据谓词未按预期工作