c++ - 这是否是一个错过的优化机会

标签 c++ compiler-optimization

我发布了this回答。代码:

#include <atomic>
#include <utility>
void printImpl(...);

std::atomic<bool> printLog = false;

class Log {
 public:
  template <typename T>
  const auto& operator<<(T&& t) {
    if (printLog) {
      ulog.active = true;
      return ulog << std::forward<T>(t);
    } else {
      ulog.active = false;
      return ulog;
    }
  }

 private:
  struct unchecked_log {
    template <typename T>
    const auto& operator<<(T&& t) const {
      if (active) {
        printImpl(std::forward<T>(t));
      }
      return *this;
    }
    bool active{false};
  };
  unchecked_log ulog{};
};

// Instead of the macro. Doesn't break backward compatibility
Log LOG;

void test(bool) { LOG << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10; }

本质上,代码要么忽略要么记录所有数据。这个想法是记录 atomic<bool>定期bool可以更容易地进行优化。我认为大多数编译器可以轻松优化 if (active)部分,因为它无法在调用之间进行更改。 Turns out不过,大多数编译器都会内联函数调用 unchecked_log::operator<<但不要优化分支。有什么东西阻止了这种优化吗?会不会违法啊。

最佳答案

LOG是具有外部链接的全局变量。因此printImpl另一个翻译单元中的定义可以到达它并可能修改 LOG.ulog.active通话之间。

制造LOG test 中的局部变量重复检查将在test条目处合并为一次。或离开LOG它在哪里并让它static ,因此包含 printImpl 的不同编译单元的定义无法到达此翻译单元的实例。

正如下面的评论中提到的,或者让 operator<<通过复制返回,因此它返回的实例(现在是临时的)对于 printImpl 是无法访问的.

<小时/>

请注意 private 的可访问性( ulog 等)和ulog.active不要紧。一旦printImpl能够获取相关实例的指针或引用,private无论如何都不能防止修改。以下是一些如何实现这一点的示例(非详尽):

  1. 调用 operator<<LOG现在可能会改变 LOG.ulog.active基于 printLog 的干预修改或通过 const_cast计算结果
  2. 调用默认的复制/移动赋值运算符
  3. (因为这是一个标准布局类)reinterpret_cast LOG对其 ulog 的引用成员(member)
  4. (因为这些类是可以简单复制的)memcpy不同的状态进入LOG
  5. placement-new Log 的新实例进入LOG ,这将使先前的引用自动引用新对象,因为 Log满足条件
  6. 等等

关于c++ - 这是否是一个错过的优化机会,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59291618/

相关文章:

c++ - 使用 Console::WriteLine() 的 Windows char 和 Char 类型和字符串

C++ 函数作用域静态变量究竟何时初始化?

compiler-construction - 如何使用 CMake 更改文件夹的编译标志?

c++ - 是否在 C++ 中访问未从函数可观察行为外部访问的 volatile 局部变量?

C# 编译器优化循环?

c++ - 如何使用 C++ 中的函数更新结构的值?

c++ - 在 C++ 中,如何在 MacOS X 中将程序与 libpng/zlib/loadpng 链接?

c++ - 将临时变量绑定(bind)到视觉上的非 const 引用编译

gcc - 迭代和取消引用未对齐的内存指针会导致段错误吗? GCC 优化器中的错误?

c++ - 可以在 macOS 上启用的最低支持 SSE 标志是什么?