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

在pybind11中为含Pet指针vector的Zoo类实现深拷贝遇编译错误求助

解决pybind11绑定Zoo类__deepcopy__的编译错误与深拷贝实现问题

编译错误核心原因

  • Zoo类的拷贝构造函数参数为Zoo&(非const左值引用),pybind11在调用拷贝逻辑时无法匹配该参数类型,导致构造函数无法被正确调用。
  • 拷贝构造函数内部存在悬垂指针问题:循环中创建的Pet new_pet是栈上局部对象,循环结束后会被销毁,存入vector的指针将变为无效地址。

修复后的C++类代码

#include <vector>
#include <string>

class Pet {
public:
    // 构造函数参数改为const引用,消除只能传递左值的限制
    Pet(const std::string &name) : name(name) {}
    // set_name参数改为const引用
    void set_name(const std::string &name_) { name = name_;}
    // get_name返回const引用提升安全性
    const std::string &get_name () const { return name; }
private:
    std::string name;
};

class Zoo {
public:
    Zoo() {}

    // 修正拷贝构造函数:参数改为const引用,正确创建堆上Pet实例
    Zoo(const Zoo& other_zoo){
        for (const auto& pet_ptr : other_zoo.pets){
            pets.push_back(new Pet(pet_ptr->get_name()));
        }
    }

    // 添加析构函数,释放堆上的Pet指针,避免内存泄漏
    ~Zoo(){
        for (auto& pet_ptr : pets){
            delete pet_ptr;
        }
        pets.clear();
    }

    // 禁用默认赋值运算符,避免浅拷贝导致的指针共享问题
    Zoo& operator=(const Zoo&) = delete;

    void set_pets(const std::vector<Pet*>& pets_) {
        // 先释放原有Pet实例,再拷贝新的
        for (auto& pet_ptr : pets){
            delete pet_ptr;
        }
        pets.clear();
        for (const auto& pet_ptr : pets_){
            pets.push_back(new Pet(pet_ptr->get_name()));
        }
    }

    const std::vector<Pet*>& get_pets () const {return pets;}

private:
    std::vector<Pet*> pets;
};

修复后的pybind11绑定代码

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    py::class_<Pet>(m, "Pet")
        .def(py::init<const std::string &>())
        .def("set_name", &Pet::set_name)
        .def("get_name", &Pet::get_name)
        .def_property("name", &Pet::get_name, &Pet::set_name)
        .def("__repr__",
             [](const Pet &a){
                return "<example.Pet named '" + a.get_name() + "'>";
             })
        ;

    py::class_<Zoo>(m, "Zoo")
        .def(py::init<>())
        .def("set_pets", &Zoo::set_pets)
        .def("get_pets", &Zoo::get_pets)
        .def_property("pets", &Zoo::get_pets, &Zoo::set_pets)
        // __deepcopy__需接收Python deepcopy传递的memo参数
        .def("__deepcopy__",
             [](const Zoo &a, py::dict memo){
                Zoo b(a);
                return b;
             })
        ;
}

Python端验证效果

import copy
from build.example import Pet, Zoo

p1 = Pet("Molly")
p2 = Pet("Charley")
z = Zoo()
z.set_pets([p1, p2])
z2 = copy.deepcopy(z)

# 修改原Pet的名字
p1.name = "Foo"

print(z.get_pets()[0].name)  # 输出 Foo
print(z2.get_pets()[0].name) # 输出 Molly,实现独立拷贝

关键补充说明

  • 析构函数的必要性:Zoo持有堆分配的Pet指针,必须手动释放避免内存泄漏。
  • 禁用赋值运算符:默认赋值运算符会执行浅拷贝,导致多个Zoo共享同一Pet指针,修改时互相影响,因此禁用避免意外。
  • memo参数的作用:Python的copy.deepcopy通过该参数处理循环引用,即使暂用不上也需在绑定中声明,否则会因参数不匹配导致调用失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:49:51