为什么这种对基本 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 的实例而不是移动它们。
我有一些类似的东西:
#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 的实例而不是移动它们。