You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何标记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;
};

为什么这两种方法满足所有要求

  1. 平凡的移动构造、移动赋值和析构:
    你的类型的移动和析构操作由编译器默认生成,依赖的辅助类/基类的对应操作都是平凡的,因此默认生成的操作也会是平凡的。

  2. 非trivially_copyable:
    根据C++标准,trivially_copyable要求所有非静态成员和基类都是trivially_copyable。辅助类/基类因为有用户定义的拷贝构造/赋值,不属于trivially_copyable,因此你的类型也会被排除在trivially_copyable之外。

  3. 符合Itanium ABI的调用平凡性:
    你的类型的析构和移动操作都是平凡的,Itanium ABI会将它们视为“调用平凡”的操作,不会生成额外的函数调用开销,性能与默认生成的平凡操作一致。

内容的提问来源于stack exchange,提问作者Marco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:42:18