这个 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->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被输入之前不会发生(other
参数的初始化只是一个引用绑定)。当然,在评估对象表达式 m[p->s]
之前,不能输入 operator=
的主体。
所以您的代码在所有版本的 C++ 中都定义良好。
【讨论】:
感谢您解决这个问题。我希望它没问题,因为它比替代品更具可读性。【参考方案2】:代码很好。在 C++ 17 中,we were given strong guarantees on the sequencing,这使得这段代码 100% OK。
在 C++17 之前的标准有
在所有情况下,赋值顺序在左右操作数的值计算之后,赋值表达式的值计算之前。
但这仍然意味着代码没问题。我们不知道m[p->s]
和std::move(p)
中的哪一个最先发生,但由于move
实际上对p
没有任何作用,所以p->s
将有效并在p
移动到@ 之前得到解决987654328@
【讨论】:
此引用适用于内置赋值运算符,不是吗? @chris 该特定段落适用于所有类型。 @idclev463035818 是的,std::move
只是一个演员表,所以它对p->s
发生的事情没有影响。不过,报价中确实包含的是,它保证std::move(p)
和m[p->s]
都将在实际分配发生(实际移动)发生之前进行评估
我现在在标准中看到了上下文。似乎 cppreference 将文本理解为其他意思,这让我很感兴趣。以上是关于这个 C++ 代码会一直按我的预期工作,还是不能保证执行顺序?的主要内容,如果未能解决你的问题,请参考以下文章
限制Python3 urllib请求所花费的时间:超时不能按我的预期运行
EZAudio 自定义 AudioStreamBasicDescription 没有按我的预期工作