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

C++17含std::unique_ptr的延迟创建器编译错误原因与解决方法

问题原因分析

你的代码编译失败的核心原因在于std::unique_ptr的特性:作为独占所有权的智能指针,它的拷贝构造和拷贝赋值运算符被C++标准显式删除,目的是防止多个unique_ptr同时管理同一块内存导致的双重释放问题。

当结构体包含std::unique_ptr时,编译器会自动删除该结构体的默认拷贝赋值运算符(因为成员的拷贝操作不可用)。而你的延迟创建器代码中,赋值操作大概率是直接对左值(保存的原始对象)进行赋值,编译器会尝试调用拷贝赋值运算符,但该运算符已被删除,因此触发编译错误。

解决方案

根据你是否需要保留原始对象的可用性,有两种修改方向:

1. 不需要保留原始对象:触发移动赋值

如果原始对象在赋值后不再被使用,直接用std::move()将其转换为右值,这样编译器会优先调用结构体默认生成的移动赋值运算符(包含unique_ptr的结构体默认会生成合法的移动操作,因为unique_ptr支持移动语义)。

错误代码示例

#include <memory>

struct Data {
    std::unique_ptr<int> val;
};

class DelayedCreator {
private:
    Data original;
public:
    DelayedCreator(Data d) : original(std::move(d)) {}

    void assignTo(Data* new_obj) {
        // 这里尝试调用拷贝赋值,而Data的拷贝赋值已被删除
        *new_obj = original;
    }
};

int main() {
    Data d;
    d.val = std::make_unique<int>(42);
    DelayedCreator creator(std::move(d));
    Data* pool_obj = new Data();
    creator.assignTo(pool_obj);
    return 0;
}

修改后代码

#include <memory>
#include <utility> // 引入std::move

struct Data {
    std::unique_ptr<int> val;
};

class DelayedCreator {
private:
    Data original;
public:
    DelayedCreator(Data d) : original(std::move(d)) {}

    void assignTo(Data* new_obj) {
        // 转换为右值,触发移动赋值
        *new_obj = std::move(original);
    }
};

int main() {
    Data d;
    d.val = std::make_unique<int>(42);
    DelayedCreator creator(std::move(d));
    Data* pool_obj = new Data();
    creator.assignTo(pool_obj);
    return 0;
}

2. 需要保留原始对象:实现克隆逻辑

如果需要复用原始对象,就不能移动它,此时需要为结构体手动实现克隆方法,复制内部的资源状态(比如对unique_ptr指向的内容进行深拷贝)。

修改后代码示例

#include <memory>

struct Data {
    std::unique_ptr<int> val;

    // 实现克隆方法,深拷贝内部资源
    Data clone() const {
        Data res;
        if (val) {
            res.val = std::make_unique<int>(*val);
        }
        return res;
    }
};

class DelayedCreator {
private:
    Data original;
public:
    DelayedCreator(Data d) : original(std::move(d)) {}

    void assignTo(Data* new_obj) {
        // 克隆原始对象,避免移动或拷贝
        *new_obj = original.clone();
    }
};

int main() {
    Data d;
    d.val = std::make_unique<int>(42);
    DelayedCreator creator(std::move(d));
    Data* pool_obj1 = new Data();
    creator.assignTo(pool_obj1);
    // 可以继续复用原始对象创建新实例
    Data* pool_obj2 = new Data();
    creator.assignTo(pool_obj2);
    return 0;
}
额外注意事项
  • 如果你的结构体还有其他自定义成员,确保移动操作或克隆逻辑能正确处理所有成员。
  • 内存池分配的对象要确保正确初始化(比如默认构造后再赋值),避免未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:02:45