文章目录
- 0x1 基本使用
- 0x11 初步使用
- 0x12 get()函数【获取指针指向的内存地址】
- 0x13 release()函数 【仅仅是释放所有权,但是并没有清空内存】
- 0x14 reset()函数 【旧值析构,重新设置指针】
- 0x2 迷惑点
- 0x21 迷惑点1 (拷贝赋值)
- 0x22 迷惑点2 (拷贝构造)
- 0x3 C++放弃 auto_ptr 的原因
- 0x31 原因1(拷贝行为结果不可控)
- 0x32 原因2 (不支持数组)
- 0x33 原因3 (STL容器不兼容)
- 0x4 为了解决auto_ptr问题,引入unique_ptr
auto_ptr是最早的智能指针,在c++98引入,c++11停用,c++14废弃,C++17正式移除
本文在实践的角度上解释来龙去脉
0x1 基本使用
0x11 初步使用
// 方法1
{int *p = new int(4);auto_ptr<int> aptr0(p);auto_ptr<int> aptr1(p); // run error cout << *aptr0 << endl; // 使用指针指向的内容
}// 方法2:
{auto_ptr<int> aptr9(new int(3));cout << *aptr9 << endl; // 使用指针指向的内容
}
方法1,看似使用起来更方便,但是如果多次使用p初始化auto_ptr,在运行时退出作用域时,会出现重复释放内存的错误,如果使用方法1,一定要保证只能被一次初始化
方法2,推荐使用
0x12 get()函数【获取指针指向的内存地址】
{int *p = new int(4);auto_ptr<int> aptr0(p);cout << aptr0.get() << endl; // 输出地址 0x8000284d0cout << p << endl; // 输出地址 0x8000284d0cout << &p << endl; // 0xffffcbd8
}
0x13 release()函数 【仅仅是释放所有权,但是并没有清空内存】
{int *ptr3 = new int(3);int *ptr4 = new int(4);auto_ptr<int> aptr5(ptr3);cout << *aptr5 << endl;aptr5.release();// release仅仅是释放所有权,但是并没有清空内存cout << *aptr5 << endl; // run error
}
0x14 reset()函数 【旧值析构,重新设置指针】
{int *ptr3 = new int(3);int *ptr4 = new int(4);auto_ptr<int> aptr6(ptr3);cout << *aptr6 << endl;aptr6.reset(ptr4);// reset 旧值析构,重新设置指针cout << *aptr6 << endl;
}
0x2 迷惑点
0x21 迷惑点1 (拷贝赋值)
[ unique_ptr 通过禁止拷贝赋值 ]
赋值后影响aptr3的继续使用
{// 当2个auto_ptr 发生赋值时,内部指针所有权会发生转移,// 这意味着赋值右者对象会失去所有权,内部指针被设置为nullauto_ptr<int> aptr3(new int(111));auto_ptr<int> aptr4(new int(222));cout << *aptr3 << endl;cout << *aptr4 << endl;aptr4 = aptr3;cout << *aptr3 << endl; // 此值为 null, 不可以使用nullptr判断,运行失败cout << *aptr4 << endl;
}
0x22 迷惑点2 (拷贝构造)
[ unique_ptr 通过禁止拷贝构造 ]
拷贝构造后影响aptr5的继续使用
{int *ptr3 = new int(3);int *ptr4 = new int(4);auto_ptr<int> aptr5(ptr3);cout << *aptr5 << endl;auto_ptr<int> aptr6(aptr5);cout << *aptr5 << endl; // RUN ERRORcout << *aptr6 << endl;
}
0x3 C++放弃 auto_ptr 的原因
0x31 原因1(拷贝行为结果不可控)
[ auto_ptr作为参数时 copy赋值后会被释放 ]
auto_ptr的拷贝行为是通过移动语义实现的,即内存所有权从一个auto_ptr对象转移到另一个auto_ptr对象。
由于auto_ptr没有提供拷贝构造函数和拷贝赋值运算符,它们会被编译器默认为移动构造函数和移动赋值运算符。【参考 0x2迷惑点 章节】
这意味着当将一个auto_ptr对象赋值给另一个auto_ptr对象时,源对象将失去对内存的控制权,可能导致程序出现不可预期的行为或内存泄漏。
void foo_test(auto_ptr<int> p2) {cout << *p2 << endl;
}
{auto_ptr<int> p1 = auto_ptr<int>(new int(3));// copy赋值后,p2会会被释放掉foo_test(p1);cout << *p1 << endl;
}
0x32 原因2 (不支持数组)
auto_ptr只能管理单个对象的动态内存分配,不能管理数组类型的动态内存分配。
如果使用auto_ptr来管理数组类型的动态内存分配,可能会导致内存泄漏或其他问题。
0x33 原因3 (STL容器不兼容)
由于auto_ptr的拷贝行为是移动语义,它不能与STL容器(如vector、map等)一起使用,否则可能会导致内存泄漏或其他问题。
[ auto_ptr作为vector的value,不能push进去 ]
// 编译失败
vector<auto_ptr<int>> Array;
auto_ptr<int> p(new int(3));
Array.push_back(p);