带release()方法的接口用protected析构器的合理性及pybind11绑定问题
C++接口设计与pybind11绑定问题解答
场景与代码实现
我正在开发一个带有extern "C"工厂方法和release纯虚方法的接口,目标是禁止通过基类指针直接调用delete,转而使用release方法。
接口代码
class IMyInterface { public: virtual void release() = 0; protected: ~IMyInterface() = default; };
派生类代码
class MyConcreteImplementation final : public IMyInterface { public: void release() override { delete this; } protected: ~MyConcreteImplementation(){ // Custom cleanup code // } };
工厂方法代码
extern "C" IMyInterface* createMyInterface() { return new MyConcreteImplementation(); }
疑问解答
1. 使用protected非虚析构器是否为正确方案?
这个方案完全正确且贴合设计需求:
- protected析构器直接阻断了外部代码通过基类指针调用
delete的可能(外部无法访问protected成员),强制使用者必须通过release方法释放对象,完美实现约束目标。 - 非虚析构器在当前场景下是安全的:派生类
MyConcreteImplementation被标记为final,不会有进一步的派生类;且release方法中是通过派生类自身的this指针调用delete,会直接触发派生类的析构逻辑,不存在基类指针删除派生类对象时的析构不全问题。如果未来需要取消final标记,再考虑将析构器改为虚即可。
2. 计划用pybind11绑定该API,但文档指出无法为带非公开析构器的类创建绑定(除非使用::nodelete)。
确实需要借助pybind11的::nodelete选项适配,具体实现思路如下:
- 在绑定
IMyInterface时添加py::nodelete标记,告知pybind11不要自动管理对象生命周期,因为我们已经通过release方法手动处理内存释放。 - 必须将
release方法暴露给Python,让Python代码可以主动调用它来释放对象。
以下是简单的绑定示例:
#include <pybind11/pybind11.h> namespace py = pybind11; PYBIND11_MODULE(my_interface, m) { // 使用nodelete禁止pybind11自动删除对象 py::class_<IMyInterface, std::unique_ptr<IMyInterface, py::nodelete>>(m, "IMyInterface") .def("release", &IMyInterface::release); // 绑定工厂方法,让Python获取对象所有权 m.def("create_my_interface", &createMyInterface, py::return_value_policy::take_ownership); }
这里用std::unique_ptr结合py::nodelete,确保pybind11不会自动调用delete;return_value_policy::take_ownership让Python接管对象,但必须手动调用release才能完成释放。
内容的提问来源于stack exchange,提问作者lielb
相关产品推荐
相关产品推荐

