为什么这种对基本 class 数据成员的访问被视为类型双关(在优化构建中)?

Why is this access of base class data members deemed to be type punning (in optimized builds)?

我有一些类似的东西:

#include <utility>
#include <cstdlib>

struct Core
{
  void* mData{};
  size_t mCount{};
};

template <typename T>
struct Actual: protected Core
{
  Actual() = default;

  Actual(Actual<T> const& other) = delete;
  Actual<T>& operator=(Actual<T> const& other) = delete;

  Actual(Actual<T>&& other):
    Core{ other.mData, other.mCount }
  {
    other.mData = nullptr;
    other.mCount = 0;
  }

  Actual<T>& operator=(Actual<T>&& other)
  {
    Actual<T> tmp(std::move(other));
    std::swap(mData, tmp.mData);    // with -O2 -Wall -Wextra -Werror: "error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]"
    mCount = tmp.mCount;            // ditto
    return *this;
  }      

  ~Actual() { /* delete[] mData as array of T, if it was created */ }

  // rest of the API incl. allocating that array of T into mData, not relevant
};

int main() {
  Actual<int> a;
  Actual<int> b;
  b = std::move(a);
}

这可以很好地编译 直到 请求优化(-O2 及以上)。

问题很简单,为什么编译器 (GCC 9.3.0) 认为这是类型双关/违反严格的别名规则,我该如何解决这个问题?

看起来像是 GCC 错误。 GCC 9.4 和更新版本不诊断这个。

如果你这样重写operator=,它就会停止抱怨,而且这个表格也会更短。

Actual<T>& operator=(Actual<T> other)
{
    std::swap(mData, other.mData);
    std::swap(mCount, other.mCount); // I like this more than `mCount = tmp.mCount;`.
    return *this;
}

要使其正常工作,您必须删除 Actual<T>& operator=(Actual<T> const& other) = delete;,您也可以删除 Actual(Actual<T> const& other) = delete;

您还应该将 noexcept 添加到移动构造函数和此赋值运算符,以免标准容器(在调整大小时)决定复制 class 的实例而不是移动它们。