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

构造函数私有且拷贝构造被删除时,如何不修改类实现在堆上创建实例

解法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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:15:03