自学内容网 自学内容网

C++:智能指针 [auto_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;    // 输出地址 0x8000284d0
    cout << p << endl;              // 输出地址 0x8000284d0
    cout << &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 发生赋值时,内部指针所有权会发生转移,
    // 这意味着赋值右者对象会失去所有权,内部指针被设置为null
    auto_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 ERROR
    cout << *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);

0x4 为了解决auto_ptr问题,引入unique_ptr


原文地址:https://blog.csdn.net/Wong_Tkpzrl/article/details/140587813

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!