auto_ptr使用介绍

1 auto_ptr使用介绍

auto_ptr 是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 获得(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来释放内存!

使用建议:

  1. 尽可能不要将auto_ptr 变量定义为全局变量或指针。
  2. 除非自己知道后果,不要把auto_ptr 智能指针赋值给同类型的另外一个智能指针。
  3. C++11 后auto_ptr 已经被“抛弃”,已使用unique_ptr替代!

示例代码如下:

#include <iostream>
#include <string>
#include  <exception>
#include <memory>

using namespace std;

//auto_ptr< Test> t(new Test());  //忠告1: 智能指针不要定义为全局变量

class Test
{
public:
    Test() {
        cout << "Test is construct" << endl;
        debug = 1; 
    }

    ~Test() { cout << "Test is destruct" << endl; }

    int getDebug() {
        return debug;
    }

private:
    int debug;
};

//用  法:    auto_ptr<类型> 变量名(new 类型)

void memory_leak_demo1() {
    auto_ptr< Test> t(new Test());

    //忠告3: 除非自己知道后果,不要把auto_ptr 智能指针赋值给同类型的另外一个智能指针
    //auto_ptr< Test> t1;
    //t1 = t;

    //auto_ptr<Test>* tp = new auto_ptr<Test>(new Test()); //忠告2: 不要定义指向智能指针对象的指针变量

    //在使用智能指针访问对象时,使用方式和普通指针一样
    cout<< "-> debug: "<<t->getDebug()<< endl;
    cout << "* debug: " << (*t).getDebug() << endl;

    //Test* tmp = t.get();
    //cout << "get debug: " << tmp->getDebug() << endl;

    //release 取消指针指针对动态内存的托管,之前分配的内存必须手动释放
    //Test*  tmp = t.release();  
    //delete tmp; 

    //reset 重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉
    //t.reset();
    t.reset(new Test());
    
    if(0){
        Test* t1 = new Test();
        t1->getDebug();
    }

    return;

}


int memory_leak_demo2() {
    //Test* t = new Test();
    auto_ptr< Test> t(new Test());

    /***********************************************
     * 程序执行一段复杂的逻辑,假设尝试从一个必须存在
     * 的文件中读取某些数据,而文件此时不存在
     ************************************************/
    {
        throw exception("文件不存在");
    }
    
    //delete t;
    return 0;
}


int main()
{
    memory_leak_demo1();

    /*try {
        memory_leak_demo2();
    }
    catch (exception e) {
        cout << "catch exception: " << e.what() << endl;
    }*/

    system("pause");
    return 0;
}

auto_ptr的源码如下,虽然不能完全看懂还是贴在这里:

#if _HAS_AUTO_PTR_ETC
// CLASS TEMPLATE auto_ptr
template <class _Ty>
class auto_ptr;

template <class _Ty>
struct auto_ptr_ref { // proxy reference for auto_ptr copying
    explicit auto_ptr_ref(_Ty* _Right) : _Ref(_Right) {}

    _Ty* _Ref; // generic pointer to auto_ptr ptr
};

template <class _Ty>
class auto_ptr { // wrap an object pointer to ensure destruction
public:
    using element_type = _Ty;

    explicit auto_ptr(_Ty* _Ptr = nullptr) noexcept : _Myptr(_Ptr) {}

    auto_ptr(auto_ptr& _Right) noexcept : _Myptr(_Right.release()) {}

    auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept {
        _Ty* _Ptr   = _Right._Ref;
        _Right._Ref = nullptr; // release old
        _Myptr      = _Ptr; // reset this
    }

    template <class _Other>
    operator auto_ptr<_Other>() noexcept { // convert to compatible auto_ptr
        return auto_ptr<_Other>(*this);
    }

    template <class _Other>
    operator auto_ptr_ref<_Other>() noexcept { // convert to compatible auto_ptr_ref
        _Other* _Cvtptr = _Myptr; // test implicit conversion
        auto_ptr_ref<_Other> _Ans(_Cvtptr);
        _Myptr = nullptr; // pass ownership to auto_ptr_ref
        return _Ans;
    }

    template <class _Other>
    auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept {
        reset(_Right.release());
        return *this;
    }

    template <class _Other>
    auto_ptr(auto_ptr<_Other>& _Right) noexcept : _Myptr(_Right.release()) {}

    auto_ptr& operator=(auto_ptr& _Right) noexcept {
        reset(_Right.release());
        return *this;
    }

    auto_ptr& operator=(auto_ptr_ref<_Ty> _Right) noexcept {
        _Ty* _Ptr   = _Right._Ref;
        _Right._Ref = 0; // release old
        reset(_Ptr); // set new
        return *this;
    }

    ~auto_ptr() noexcept {
        delete _Myptr;
    }

    _NODISCARD _Ty& operator*() const noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        return *get();
    }

    _NODISCARD _Ty* operator->() const noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        return get();
    }

    _NODISCARD _Ty* get() const noexcept {
        return _Myptr;
    }

    _Ty* release() noexcept {
        _Ty* _Tmp = _Myptr;
        _Myptr    = nullptr;
        return _Tmp;
    }

    void reset(_Ty* _Ptr = nullptr) noexcept { // destroy designated object and store new pointer
        if (_Ptr != _Myptr) {
            delete _Myptr;
        }

        _Myptr = _Ptr;
    }

private:
    _Ty* _Myptr; // the wrapped object pointer
};

2 auto_ptr的弊端

auto_ptr是用于C++11之前的智能指针。由于 auto_ptr 基于排他所有权模式:两个指针不能指向同一个资源,复制或赋值都会改变资源的所有权。auto_ptr 主要有如下几个问题:

  • 复制和赋值会改变资源的所有权,不符合人的直觉。
  • 在 STL 容器中使用auto_ptr存在重大风险,因为容器内的元素必需支持可复制(copy constructable)和可赋值(assignable)。
  • 不支持对象数组的操作。
#include <stdio.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>

using namespace std;

int main() {

	//弊端1. auto_ptr 被C++11 抛弃的主要理由 p1= p2 ,复制或赋值都会改变资源的所有权
	auto_ptr<string> p1(new string("I 'm martin."));
	auto_ptr<string> p2(new string("I 'm rock."));
	printf("p1: %p\n", p1.get());
	printf("p2: %p\n", p2.get());

	p1 = p2;
	printf("after p1 = p2\n");
	printf("p1: %p\n", p1.get());
	printf("p2: %p\n", p2.get());

	//弊端2. 在 STL 容器中使用auto_ptr存在重大风险,因为容器内的元素必需支持可复制(copy constructable)和可赋值(assignable)。
	vector<auto_ptr<string>> va;
	auto_ptr<string> p3(new string("I 'm p3."));
	auto_ptr<string> p4(new string("I 'm p4."));

	va.push_back(std::move(p3));
	va.push_back(std::move(p4));

	cout <<"va[0]: "<< *va[0] << endl;
	cout <<"va[1]: "<< *va[1] << endl;

	//风险来啦
	va[0] = va[1];
	cout << "va[0]: " << *va[0] << endl;
	cout << "va[1]: " << *va[1] << endl;

	//弊端3. 不支持对象数组的内存管理
	//auto_ptr<int[]> ai(new int[5]);  //不能这样定义

	//auto_ptr 陷阱,不能把同一段内存交给多个auto_ptr 变量去管理
	/*{
		auto_ptr<string> p2;

		string* str = new string("智能指针的内存管理陷阱");
		p2.reset(str);
		{
			auto_ptr<string> p1;
			p1.reset(str);
		}
		cout <<"str: " << *p2 << endl;
	}*/
	


	system("pause");
	return 0;
}

所以,C++11用更严谨的unique_ptr 取代了auto_ptr!


参考资料:

  1. C/C++从入门到精通-高级程序员之路【奇牛学院】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值