如何在Pybind11中封装显式禁用拷贝的C++类(支持移动语义)
在Pybind11中封装禁用拷贝、仅允许移动的C++类
如果你的C++类已经显式禁用了拷贝构造与拷贝赋值,同时默认了移动操作:
class Foo { public: Foo(const Foo& other) = delete; Foo& operator=(const Foo& other) = delete; Foo(Foo&& other) = default; Foo& operator=(Foo&& other) = default; // 其他成员逻辑... };
要在Pybind11中严格遵循这个设计意图——强制使用移动操作、禁止拷贝,需要从两方面配置绑定逻辑:
1. 彻底禁用Python端的拷贝路径
Pybind11默认会尝试生成拷贝相关的绑定,我们需要主动拦截并禁用:
- 用
py::delete_function()标记拷贝构造函数为不可用 - 实现
__copy__和__deepcopy__方法抛出异常,阻止Python原生的复制操作
2. 绑定移动构造与移动赋值
显式绑定C++的默认移动构造和移动赋值运算符,让Python端可以正常使用移动语义。
完整绑定代码示例
#include <pybind11/pybind11.h> #include "foo.h" // 你的Foo类头文件 namespace py = pybind11; PYBIND11_MODULE(foo_module, m) { py::class_<Foo>(m, "Foo") // 禁用拷贝构造函数 .def(py::init<const Foo&>(), py::delete_function()) // 拦截Python的拷贝/深拷贝操作 .def("__copy__", [](const Foo&) { throw std::runtime_error("Foo类禁止拷贝,请使用移动操作"); }) .def("__deepcopy__", [](const Foo&, py::dict) { throw std::runtime_error("Foo类禁止深拷贝,请使用移动操作"); }) // 绑定移动构造函数 .def(py::init<Foo&&>()) // 绑定移动赋值运算符 .def("__assign__", [](Foo& self, Foo&& other) { self = std::move(other); return self; }); // 若Foo有其他构造函数(比如默认构造),正常绑定即可 // .def(py::init<>()); }
效果说明
- Python端尝试拷贝
Foo实例(比如a = Foo(); b = a或import copy; b = copy.copy(a))时,会直接抛出异常,严格遵循C++类的约束 - 移动操作可正常使用,比如通过工厂函数返回右值实例,或在Python中通过
b = Foo(std::move(a))(若你绑定了std::move接口)转移对象所有权
内容的提问来源于stack exchange,提问作者A. Fenzry
相关产品推荐
相关产品推荐

