带自定义删除器的unique_ptr以nullptr初始化后修改原始指针的疑问
unique_ptr提前绑定未初始化指针导致资源泄漏的原因
在与管理指针创建/销毁的C库交互场景中,若在原始指针指向有效内存前就用unique_ptr接管它,会导致资源泄漏,删除器无法被正确调用。以下是模拟该错误场景的代码:
#include <memory> #include <iostream> struct Foo { std::string s; }; // 模拟使用输出指针的C库函数 void init_foo(Foo** foo_ptr_ptr) { std::cout << "Initializing Foo\n"; Foo* f = new Foo; *foo_ptr_ptr = f; }; // 通过C API实现的自定义资源销毁函数 void delete_foo(Foo* foo) { std::cout << "Invoking destructor!\n"; if (foo != nullptr) { std::cout << "Deleting Foo\n"; delete foo; } } int main() { Foo * foo {nullptr}; // 错误:先创建unique_ptr,此时它接管的是nullptr std::unique_ptr<Foo, decltype(&delete_foo)> foo_ptr {foo, &delete_foo}; init_foo(&foo); // 修改的是外部原始指针,unique_ptr对此不知情 return 0; }
问题本质
unique_ptr构造时会拷贝传入的指针值(此处是nullptr)并保存为内部管理的指针,后续它只会基于这个内部指针执行销毁逻辑。- 调用
init_foo(&foo)修改的是独立的foo指针变量,而非unique_ptr内部存储的指针。unique_ptr完全不知道外部有新的资源被分配,因此析构时只会对初始的nullptr调用删除器——而delete_foo对nullptr不做任何实际释放操作,最终导致init_foo分配的Foo对象永远泄漏。 - 这种操作不属于C++标准定义的未定义行为,只是违反了
unique_ptr的使用规则:它应当接管已经指向有效资源的指针,且接管后外部不得再手动修改或管理该资源的指针。
正确实现方式
必须先通过C API初始化原始指针,确保它指向有效资源后,再交给unique_ptr接管:
int main() { Foo * foo {nullptr}; init_foo(&foo); // 先初始化指针,获取有效资源 std::unique_ptr<Foo, decltype(&delete_foo)> foo_ptr {foo, &delete_foo}; // 由unique_ptr接管资源 return 0; }
此时unique_ptr内部保存的是指向有效Foo对象的指针,析构时会调用delete_foo正确释放资源,避免泄漏。
内容的提问来源于stack exchange,提问作者xworder
相关产品推荐
相关产品推荐

