具有/不具有throw / noexcept功能的潜在C ++编译器优化

时间:2015-11-09 13:36:25

标签: c++ exception compiler-optimization throw

假设以下课程:

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;
}

我知道这不是实施operator=的最佳方式,但这是有目的的,因为我的问题是关于这两行:

    m_content = nullptr;
    m_content = getCopiedContent(rhs);

可以编译器 优化m_content = nullptr; ,即使getCopiedContent未定义为{{ 1}}或throw()

noexcept

一方面,编译器可能会假设,如果other_type* getCopiedContent(const Example& obj); 之后我用m_content = nullptr;的返回值覆盖m_content的值,它可以优化整个getCopiedContent表达。另一方面,如果编译器将其优化并且m_content = nullptr;抛出异常,getCopiedContent将包含无效值。

关于这种情况,C ++标准是否陈述任何

2 个答案:

答案 0 :(得分:4)

  

可以是编译器优化出m_content = nullptr;即使getCopiedContent未定义为throw()或noexcept:

是。这是一个没有副作用的冗余操作。任何自尊的编译器都会优化冗余存储。实际上,您必须非常努力地保持冗余存储不被优化,例如:

  1. 使它std::atomic(如果它是原子的,写入必须传输到其他线程)
  2. 制作volatile
  3. 使用某种内存屏障(例如锁定std::mutex)包围写入的原因与(1)
  4. 相同
      

    另一方面,如果编译器对其进行优化并且getCopiedContent抛出异常,则m_content将包含无效值

    很好的观察。允许编译器在异常处理程序中执行nullptr的写入。也就是说它可以重新订购指令以便保存操作,只要总结果是“好像'它没有。

      

    C ++标准是否说明了与此类情况有关的任何内容?

    是。它有' as-if'规则。在推理一个主题时,可见的结果必须是“如果'您的每个语句都是按顺序执行的,没有针对非流水线,非缓存,非常简单的内存模型进行优化。请注意,过去20年中生产的计算机实际上并非如此简单,但程序的结果必须如此。

    有一个例外 - 复制省略。在某些情况下消除冗余副本的副作用不需要保留。例如,在删除临时和RVO期间的参数副本时。

答案 1 :(得分:0)

我相信这叫做Dead Store Elimination

除了as-if rule之外,我不知道标准中是否包含编译器优化。

这是Clang用于消除死亡商店的代码。 http://www.llvm.org/docs/doxygen/html/DeadStoreElimination_8cpp_source.html 这只会阻止本地的。

也许有一些工具可以内联函数并将分析作为块本地来查看是否可以消除nullptr存储。显然,在某个地方抛出函数会使分析保持nullptr存储。

显然,您描述的方案违反了as-if规则,因此不符合标准。