Ale*_*op. 9 c++ exception throw compiler-optimization
假设以下课程:
class Example
{
public:
...
Example& operator=(const Example& rhs);
...
private:
other_type *m_content;
size_t m_content_size;
}
Example& Example::operator=(const Example& rhs)
{
if (this != &rhs)
{
delete m_content;
m_content = nullptr;
m_content = getCopiedContent(rhs);
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
我知道这不是最好的实现方式,operator=但这是有目的的,因为我的问题是关于这两行:
m_content = nullptr;
m_content = getCopiedContent(rhs);
Run Code Online (Sandbox Code Playgroud)
可以是编译器将优化,m_content = nullptr;即使getCopiedContent未定义为throw()或noexcept:
other_type* getCopiedContent(const Example& obj);
Run Code Online (Sandbox Code Playgroud)
一方面,编译器可以假设如果在m_content = nullptr;我m_content用返回值覆盖值之后getCopiedContent,它可以优化整个m_content = nullptr;表达式.另一方面,如果编译器将其优化并getCopiedContent抛出异常,m_content则将包含无效值.
C++标准是否说明了这种情况的任何内容?
可以是编译器会优化掉 m_content = nullptr; 即使 getCopiedContent 未定义为 throw() 或 noexcept:
是的。这是一个没有副作用的冗余操作。任何自尊的编译器都会优化冗余存储。事实上,您必须非常努力地工作以防止冗余存储被优化,例如:
std::atomic(如果它是原子的,写入必须传输到其他线程)volatilestd::mutex出于与(1)相同的原因,用某种内存屏障(例如 lock a )包围写入另一方面,如果编译器对其进行优化并且 getCopiedContent 抛出异常,则 m_content 将包含一个无效值
很好的观察。允许编译器nullptr在异常处理程序中执行写入。即它可以重新排序指令以保存操作,前提是总结果“好像”它没有。
C++ 标准是否说明了有关这种情况的任何内容?
是的。它有“好像”规则。在推理一个线程时,可见的结果必须是“好像”您的每个语句都是按顺序执行的,没有针对非流水线、非缓存、非常简单的内存模型进行优化。请注意,过去 20 年生产的计算机实际上没有这么简单,但程序的结果必须如此。
对此有一个例外 - 复制省略。不需要保留在某些情况下删除冗余副本的副作用。例如,在删除临时和 RVO 期间的参数副本时。