创建不可构造对象:std::bit_cast是否应限制为隐式生存期类型?
不可构造类与
std::bit_cast的实例化问题分析 我们可以设计不可构造类,但借助std::bit_cast仅要求输入输出为trivially copyable类型的特性,能够成功实例化这类对象。
问题背景与测试代码
我试图理解为何无公开构造函数的类无法完全阻止独立对象创建,同时验证trivially copyable不意味着隐式生存期。Jarod42提示了一个仅含赋值运算符、无构造函数的类,测试代码如下:
#include <bit> #include <cstring> #include <iostream> // 不可构造、非隐式生存期类型 struct Test { int val{1}; Test() = delete; Test(Test const&) = delete; Test(Test&&) = delete; Test& operator=(Test const&) = default; Test& operator=(Test&&) = default; ~Test() = default; }; int main() { char storage[sizeof(Test)]; int i{666}; std::memcpy(storage,&i,sizeof(Test)); auto HeWhoMustNotBeNamed = std::bit_cast<Test>(storage); std::cout << HeWhoMustNotBeNamed.val; }
编译器行为与类型判定
测试的gcc、clang、msvc均正确识别Test为trivially copyable类型,判定依据:
- 具备符合条件的平凡拷贝和移动赋值运算符;
- 无其他符合条件的特殊成员;
- 存在平凡且未删除的构造函数。
Test与storage满足std::bit_cast的前置条件,因此clang和msvc可无未定义行为地创建该不可构造类的对象,我认为此行为违反类语义,并不合理。(注:gcc执行失败,推测是未执行拷贝省略,需要不可用的移动构造函数)
隐式生存期类型的判定
Test并非隐式生存期类型,依据C++标准:
- 存在用户声明的构造函数,因此不是聚合类型;
- 无符合条件的平凡构造函数(均已删除)。
而std::start_lifetime_as要求输出为隐式生存期类型(甚至要求是聚合类型,似乎过于严格),因此我认为std::bit_cast应限制输出类型为隐式生存期类型,输入类型的限制则有待商榷。
实际应用场景
此问题并非纯理论,不可构造类可作为仅用于继承的基实现类,示例如下:
// 不可构造、非隐式生存期类型 struct BaseImpl { int val{1}; BaseImpl() = delete; BaseImpl(BaseImpl const&) = delete; BaseImpl(BaseImpl&&) = delete; BaseImpl& operator=(BaseImpl const&) = default; BaseImpl& operator=(BaseImpl&&) = default; ~BaseImpl() = default; protected: BaseImpl(int i) : val{i} {}; }; struct Concrete: private BaseImpl { Concrete(int i) : BaseImpl{i}{}; int Value() const {return BaseImpl::val;}; };
补充思考:访问说明符的影响
特殊成员函数的访问说明符不属于trivially copyable或隐式生存期类型的定义,因此如下类同时满足这两个特性,让合理的要求制定更复杂:
class Test { int val; Test() = default; Test(Test const&) = default; Test(Test&&) = default; Test& operator=(Test const&) = default; Test& operator=(Test&&) = default; ~Test() = default; };
我的分析是否存在错误?
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

