构造函数私有且拷贝构造被删除时,如何不修改类实现在堆上创建实例
解法1(C++17及以上版本,推荐,无额外开销)
利用C++17引入的强制复制消除特性,可以直接在堆内存上构造实例,完全不需要拷贝/移动构造函数参与,写法如下:
#include <memory> int main() { // 普通指针版本 MyStruct* ptr = new auto(MyStruct::Create(2)); // 用完记得手动delete释放内存 // delete ptr; // unique_ptr智能指针版本 std::unique_ptr<MyStruct> uptr(new auto(MyStruct::Create(2))); return 0; }
原理说明
C++17规定,当用纯右值初始化同类型对象时,会直接将对象构造在目标内存地址上,不需要调用拷贝或移动构造函数,哪怕这两个函数被删除也不影响。MyStruct::Create返回的是MyStruct类型的纯右值,new auto(...)会直接把返回的实例构造在堆分配的内存上,完全规避了私有的构造函数和删除的拷贝构造限制。
注意:无法直接使用
std::make_unique实现该需求,因为std::make_unique内部需要调用类的公开构造函数,而MyStruct的构造函数是私有属性,题目要求不能修改类实现因此无法做友元声明。
解法2(兼容C++11/14,仅适用于平凡可复制类型)
如果你使用的编译器不支持C++17,且MyStruct属于平凡可复制类型(你的示例满足该条件:成员都是基础类型、无虚函数、无自定义析构),可以用栈上构造后内存拷贝的方式实现:
#include <memory> #include <cstring> #include <utility> int main() { // 先在栈上构造实例 alignas(MyStruct) char buf[sizeof(MyStruct)]; new (buf) auto(MyStruct::Create(2)); // 拷贝到堆内存 MyStruct* ptr = static_cast<MyStruct*>(operator new(sizeof(MyStruct))); std::memcpy(ptr, buf, sizeof(MyStruct)); // 封装为unique_ptr的写法 std::unique_ptr<MyStruct> uptr(ptr); // 手动析构栈上的临时实例 std::destroy_at(reinterpret_cast<MyStruct*>(buf)); return 0; }
注意事项
该方案仅适用于平凡可复制类型,如果MyStruct有自定义析构、虚函数、非平凡成员等场景,会触发未定义行为,优先使用C++17的解法。
内容的提问来源于stack exchange,提问作者mpen
相关产品推荐
相关产品推荐

