如何标记C++类型为非trivially_copyable且符合Itanium ABI调用平凡性?
解决方案:实现仅移动且非
trivially_copyable的类型,同时保留ABI兼容性 要同时满足你提出的三个目标,核心思路是破坏trivially_copyable的判定条件,但不影响移动操作和析构的平凡性。具体可以通过添加一个非trivially_copyable但移动/析构平凡的辅助成员或基类来实现,同时利用空基类优化(EBO)或C++20的[[no_unique_address]]避免额外内存开销。
方法1:使用辅助成员(C++20及以上)
定义一个标记类,它的拷贝构造/赋值是用户定义的(非平凡),但移动构造/赋值和析构是默认生成的(平凡):
struct NonTrivialCopyableMarker { NonTrivialCopyableMarker() = default; // 用户定义拷贝构造,使该类非trivially_copyable NonTrivialCopyableMarker(const NonTrivialCopyableMarker&) {} // 平凡移动构造 NonTrivialCopyableMarker(NonTrivialCopyableMarker&&) = default; // 用户定义拷贝赋值,强化非trivially_copyable属性 NonTrivialCopyableMarker& operator=(const NonTrivialCopyableMarker&) {} // 平凡移动赋值 NonTrivialCopyableMarker& operator=(NonTrivialCopyableMarker&&) = default; // 平凡析构 ~NonTrivialCopyableMarker() = default; };
将该标记类作为你的类型的成员,并用[[no_unique_address]]修饰以避免占用额外内存:
class MyType { public: MyType() = default; // 禁用拷贝操作 MyType(const MyType&) = delete; MyType& operator=(const MyType&) = delete; // 保留平凡移动构造 MyType(MyType&&) = default; // 保留平凡移动赋值 MyType& operator=(MyType&&) = default; // 保留平凡析构 ~MyType() = default; private: // 标记类不占用额外内存 [[no_unique_address]] NonTrivialCopyableMarker marker; // 你的实际数据成员 int data; };
方法2:使用辅助基类(兼容C++11及以上)
如果需要兼容C++20之前的标准,可以将标记类作为私有基类,利用空基类优化(EBO)避免内存开销:
struct NonTrivialCopyableBase { NonTrivialCopyableBase() = default; NonTrivialCopyableBase(const NonTrivialCopyableBase&) {} NonTrivialCopyableBase(NonTrivialCopyableBase&&) = default; NonTrivialCopyableBase& operator=(const NonTrivialCopyableBase&) {} NonTrivialCopyableBase& operator=(NonTrivialCopyableBase&&) = default; ~NonTrivialCopyableBase() = default; }; class MyType : private NonTrivialCopyableBase { public: MyType() = default; MyType(const MyType&) = delete; MyType& operator=(const MyType&) = delete; MyType(MyType&&) = default; MyType& operator=(MyType&&) = default; ~MyType() = default; private: int data; };
为什么这两种方法满足所有要求
平凡的移动构造、移动赋值和析构:
你的类型的移动和析构操作由编译器默认生成,依赖的辅助类/基类的对应操作都是平凡的,因此默认生成的操作也会是平凡的。非
trivially_copyable:
根据C++标准,trivially_copyable要求所有非静态成员和基类都是trivially_copyable。辅助类/基类因为有用户定义的拷贝构造/赋值,不属于trivially_copyable,因此你的类型也会被排除在trivially_copyable之外。符合Itanium ABI的调用平凡性:
你的类型的析构和移动操作都是平凡的,Itanium ABI会将它们视为“调用平凡”的操作,不会生成额外的函数调用开销,性能与默认生成的平凡操作一致。
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

