在 C++ 中,std::make_unique用于动态分配对象并返回一个std::unique_ptr,但它本身不直接支持复制构造对象,因为make_unique会创建一个新的独立对象。如果你需要将一个已有对象复制到另一个unique_ptr管理的对象中,通常需要以下步骤:

1.直接复制对象(不推荐)
如果目标对象是可拷贝构造的,你可以先复制对象,再用make_unique管理它:

 #include <memory>
#include <iostream>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    MyClass(const MyClass& other) : value(other.value) { // 拷贝构造函数
        std::cout << "Copy constructed" << std::endl;
    }
};

int main() {
    MyClass obj1(42);

    // 方法1:显式拷贝构造,再用 make_unique 管理
    auto obj2_ptr = std::make_unique<MyClass>(obj1); // 调用拷贝构造函数

    std::cout << obj2_ptr->value << std::endl; // 输出: 42
    return 0;
}

缺点:
• 需要显式调用拷贝构造函数,可能不够直观。
• 如果MyClass的拷贝构造函数是私有的或删除的,此方法会失败。

2.通过unique_ptr的reset或直接构造
如果源对象本身由unique_ptr管理,可以通过reset或直接构造新指针:

 #include <memory>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    MyClass(const MyClass& other) : value(other.value) {}
};

int main() {
    auto src_ptr = std::make_unique<MyClass>(42);

    // 方法2:通过 reset 或直接构造
    auto dest_ptr = std::make_unique<MyClass>(*src_ptr); // 调用拷贝构造函数

    std::cout << dest_ptr->value << std::endl; // 输出: 42
    return 0;
}

3.使用std::unique_ptr的移动语义(不复制)
如果不需要复制,而是转移所有权,可以直接用std::move:

 auto src_ptr = std::make_unique<MyClass>(42);
auto dest_ptr = std::move(src_ptr); // 转移所有权,src_ptr 变为 nullptr

if (!src_ptr) {
    std::cout << "src_ptr is now empty" << std::endl;
}
std::cout << dest_ptr->value << std::endl; // 输出: 42

4.自定义克隆函数(推荐)
如果需要动态复制unique_ptr管理的对象,可以定义一个克隆函数(如clone()),返回新的unique_ptr:

 #include <memory>

class MyClass {
public:
    int value;
    MyClass(int v) : value(v) {}
    MyClass(const MyClass& other) : value(other.value) {}

    // 定义克隆函数
    std::unique_ptr<MyClass> clone() const {
        return std::make_unique<MyClass>(*this);
    }
};
int main() {
    auto src_ptr = std::make_unique<MyClass>(42);

    // 方法4:通过克隆函数复制
    auto dest_ptr = src_ptr->clone();

    std::cout << dest_ptr->value << std::endl; // 输出: 42
    return 0;
}

优点:
• 代码清晰,直接表达“复制”语义。
• 适用于复杂对象或需要深拷贝的场景。

总结

方法 适用场景 是否调用拷贝构造函数
make_unique(obj) 从已有对象构造新 unique_ptr ✅ 是
reset 或直接构造 从另一个 unique_ptr 复制 ✅ 是
std::move 转移所有权(不复制) ❌ 否(原指针变为空)
自定义 clone() 函数 需要灵活控制复制逻辑 ✅ 是

注意事项
1.性能:拷贝构造可能触发深拷贝(如对象持有动态资源),需确保拷贝构造函数正确实现。
2.异常安全:make_unique是异常安全的,但直接拷贝构造需确保源对象有效。
3.多态支持:如果基类指针指向派生类对象,需通过虚函数实现多态克隆(见下文扩展)。

扩展:多态对象的克隆
如果涉及继承,可以通过基类虚函数实现多态克隆:

 class Base {
public:
    virtual ~Base() = default;
    virtual std::unique_ptr<Base> clone() const = 0;
};

class Derived : public Base {
public:
    int value;
    Derived(int v) : value(v) {}
    std::unique_ptr<Base> clone() const override {
        return std::make_unique<Derived>(*this);
    }
};

int main() {
    std::unique_ptr<Base> src = std::make_unique<Derived>(42);
    auto dest = src->clone(); // 多态克隆
    return 0;
}

这样,无论src指向哪种派生类,clone()都能正确复制对象。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐