C++14中如何阻止sizeof运算符作用于完整类型并触发编译错误
可行方案
因为sizeof是C内置运算符,不支持重载,所以你最初尝试的运算符删除写法是不生效的,目前有两类符合C14标准的方案可以实现需求,分别适用于不同的场景:
方案1:Pimpl惯用法(无hack,可靠性最高)
如果你可以接受自定义类型对外只暴露不完整声明,用Pimpl(指针指向实现)的方式封装,就可以从语法层面完全阻止外部代码对实现类使用sizeof:
// 对外暴露的头文件 my_class.h class MyClass { public: MyClass(); ~MyClass(); // 对外暴露的所有接口声明 void do_something(); int get_value() const; private: struct Impl; // 仅前置声明,无完整定义 Impl* impl_; };
// 内部实现文件 my_class.cpp #include "my_class.h" // 实现类的完整定义仅在cpp内可见,外部完全无法访问 struct MyClass::Impl { int data = 0; // 其他内部成员、方法 }; // 所有对外接口的实现都转发到内部impl MyClass::MyClass() : impl_(new Impl()) {} MyClass::~MyClass() { delete impl_; } void MyClass::do_something() { impl_->data++; } int MyClass::get_value() const { return impl_->data; }
这个方案的特性:
- 完全符合C++标准,无任何hack,全编译器兼容
- 外部代码只能看到
MyClass::Impl的前置声明,属于不完整类型,任何对MyClass::Impl使用sizeof的代码都会直接触发编译错误 - 如果连对外的
MyClass本身的sizeof也要禁止,可以进一步只对外暴露MyClass的前置声明,只返回指针/引用类型的访问接口:// 头文件中仅保留声明,无类定义 #include <memory> class MyClass; std::unique_ptr<MyClass> create_my_class(); void my_class_do_something(MyClass* obj);
方案2:宏替换hack(类完整定义可见的场景下生效)
如果你必须让自定义类的完整定义对外可见,可以用宏替换sizeof做编译期检查,只要在你要生效的代码作用域内定义如下宏即可:
#include <type_traits> // 你的自定义类 class ForbidSizeofClass { public: int a; void func() {} // 其他类成员定义 }; // 放在头文件末尾,必须在所有系统、标准库头文件引入之后定义 #define sizeof(...) \ static_assert( \ !std::is_same<typename std::decay<decltype(__VA_ARGS__)>::type, ForbidSizeofClass>::value, \ "sizeof is forbidden on ForbidSizeofClass" \ ); \ sizeof(__VA_ARGS__)
这个方案的限制:
- 必须在包含所有系统、标准库头文件之后定义该宏,否则会破坏标准库内部的
sizeof使用 - 宏仅在定义之后的代码中生效,未包含这个宏定义的翻译单元不受影响
- 可以通过写
::sizeof的方式绕过检查,但常规编码场景下几乎不会出现这种写法 - 如果要支持禁止多个类型的
sizeof,在静态断言的判断条件中扩展即可。
内容的提问来源于stack exchange,提问作者CoffeeTableEspresso
相关产品推荐
相关产品推荐

