怎样正确构造一个auto_ptr?

一个auto_ptr该如何构造?如果你写std::auto_ptr<Foo> foo = new Foo;会死得很惨,而且有两种死法。第一种死法温柔点,只是编译不过;第二种是编译正常,但运行时崩溃。具体会出现哪种死法,取决于你的编译器,比如用g++就是第一种,用VC是第二种。

正确的构造方式应该是std::auto_ptr<Foo> foo(new Foo)(或者从另一个auto_ptr来拷贝构造),上面提到的那种写法之所以不正确,是因为auto_ptr(T * t=NULL)这个构造函数声明为explicit的,但是在VC里为什么又能编译通过呢?VC遇到这种写法时,它会发现可以用new出来的Foo类型的指针,隐式构造一个auto_ptr_ref对象,然后把这个auto_ptr_ref做为auto_ptr的构造参数。因为VC定义auto_ptr_ref的构造函数时,并没有explicit限定。g++要贴心点,它有这个限制。

`std::unique_ptr` 是 C++11 引入的智能指针之一,用于管理动态分配的对象,确保在任何情况下(包括异常)都能自动释放资源,从而防止内存泄漏。它通过独占所有权语义来保证同一时间只有一个 `unique_ptr` 拥有该对象。 --- ### ✅ 正确使用 `std::unique_ptr` 的方法: #### 1. **创建 `unique_ptr`** 推荐使用 `std::make_unique`(C++14 起正式支持)来创建 `unique_ptr`,避免裸 `new`。 ```cpp #include <memory> #include <iostream> class MyClass { public: MyClass() { std::cout << "MyClass constructed\n"; } ~MyClass() { std::cout << "MyClass destructed\n"; } void sayHello() { std::cout << "Hello from MyClass!\n"; } }; // 推荐方式:使用 make_unique auto ptr = std::make_unique<MyClass>(); ptr->sayHello(); // 自动析构,无需 delete ``` > ⚠️ 注意:C++11 不自带 `make_unique`,但 C++14 起已加入标准库。 #### 2. **不能复制,但可以移动** `unique_ptr` 禁止拷贝构造和拷贝赋值,但支持移动语义。 ```cpp auto ptr1 = std::make_unique<MyClass>(); // auto ptr2 = ptr1; // 错误!不能拷贝 auto ptr2 = std::move(ptr1); // 正确!转移所有权 // 此时 ptr1 为空,ptr2 拥有对象 if (!ptr1) { std::cout << "ptr1 is null\n"; } ``` #### 3. **作为函数参数传递** - 如果函数要**接管所有权**,使用右值引用或直接接收 `unique_ptr`。 - 如果只是**临时使用对象**,应传递引用或原始指针。 ```cpp void useByPointer(MyClass* obj) { if (obj) obj->sayHello(); } void takeOwnership(std::unique_ptr<MyClass> obj) { obj->sayHello(); // 函数结束时自动释放 } int main() { auto ptr = std::make_unique<MyClass>(); useByPointer(ptr.get()); // 仅借用,不转移所有权 takeOwnership(std::move(ptr)); // 转移所有权 // 此时 ptr 已为空 return 0; } ``` #### 4. **作为函数返回值(常用)** 函数可以安全地返回 `unique_ptr`,编译器会优化移动操作。 ```cpp std::unique_ptr<MyClass> createMyClass() { return std::make_unique<MyClass>(); } int main() { auto ptr = createMyClass(); // 移动被隐式处理 ptr->sayHello(); return 0; } ``` #### 5. **管理数组(可选)** 虽然 `unique_ptr` 可以管理数组,但通常更推荐 `std::vector` 或 `std::array`。如果必须用数组,需指定数组删除器。 ```cpp std::unique_ptr<int[]> arr(new int[10]); arr[0] = 42; arr[1] = 99; // 自动调用 delete[] ``` 或者使用别名简化: ```cpp using IntArray = std::unique_ptr<int[]>; IntArray arr = std::make_unique<int[]>(10); ``` #### 6. **自定义删除器(高级用法)** 可用于释放非内存资源(如文件句柄、socket 等)。 ```cpp struct FileDeleter { void operator()(FILE* file) const { if (file) { std::fclose(file); std::cout << "File closed\n"; } } }; std::unique_ptr<FILE, FileDeleter> filePtr(std::fopen("test.txt", "w")); if (filePtr) { fprintf(filePtr.get(), "Hello, world!\n"); } // 文件在作用域结束时自动关闭 ``` --- ### ❗常见错误与注意事项 | 错误 | 说明 | |------|------| | 使用裸 `new` 而不用 `make_unique` | 容易造成异常安全问题(如表达式中部分构造失败) | | 尝试拷贝 `unique_ptr` | 编译错误,应使用 `std::move` | | 忘记 `std::move` 导致无法传递所有权 | 所有权未转移,原指针仍持有资源 | | 混淆 `get()` 和 `release()` | `get()` 返回原始指针但不释放所有权;`release()` 放弃所有权但不释放内存 | --- ### ✅ 最佳实践总结 1. 始终优先使用 `std::make_unique<T>(...)` 创建对象。 2. 不要用 `new` 显式构造 `unique_ptr`,除非有特殊删除器。 3. 传递时尽量使用 `T*` 或 `const T&` 借用,避免不必要的移动。 4. 函数返回动态对象时,返回 `unique_ptr` 是最佳选择。 5. 避免长期持有空的 `unique_ptr`,及时检查有效性。 ---
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值