zoukankan      html  css  js  c++  java
  • C++11 auto_ptr 的问题

    auto_ptr作为最早的智能指针,可以实现以RAII手法管理堆区对象,但它设计的本意只是简单的利用C++对于栈区对象的自动析构管理堆区对象,

    并不像shared_ptr那样包含引用计数,可以在每次拷贝的时候多出一个“分身”。这时候,拷贝的语义就成了很大的问题(按理说直接禁掉可能好好些),

    于是就出现了下面这个不伦不类的原型:

    explicit auto_ptr (X* p=0) throw();
    auto_ptr (auto_ptr& a) throw();
    template<class Y>
      auto_ptr (auto_ptr<Y>& a) throw();
    auto_ptr (auto_ptr_ref<X> r) throw();
    auto_ptr& operator= (auto_ptr& a) throw();
    template <class Y>
      auto_ptr& operator= (auto_ptr<Y>& a) throw();
    auto_ptr& operator= (auto_ptr_ref<X> r) throw();

    这个跟一般我们定义一个类的拷贝(构造和赋值)函数就不一样了:

    class foo
    {
        foo(const foo& a);
       foo& operator=(const foo& a);
    }

    关键在于少了const,而每当auto_ptr被拷贝,它都会被置为null,相当于“移动”的语义。

    这样不仅违反直觉,而且在C++11里有了正统的移动语义的情况下更显得奇怪,于是重新设计了unque_ptr

    ,改动不大,只是把语义纠正过来了,

    default (1)    
    
    constexpr unique_ptr() noexcept;
    
    from null pointer (2)    
    
    constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}
    
    from pointer (3)    
    
    explicit unique_ptr (pointer p) noexcept;
    
    from pointer + lvalue deleter (4)    
    
    unique_ptr (pointer p,
        typename conditional<is_reference<D>::value,D,const D&> del) noexcept;
    
    from pointer + rvalue deleter (5)    
    
    unique_ptr (pointer p,
        typename remove_reference<D>::type&& del) noexcept;
    
    move (6)    
    
    unique_ptr (unique_ptr&& x) noexcept;
    
    move-cast (7)    
    
    template <class U, class E>
      unique_ptr (unique_ptr<U,E>&& x) noexcept;
    
    move from auto_ptr (8)    
    
    template <class U>
      unique_ptr (auto_ptr<U>&& x) noexcept;
    
    copy (deleted!) (9)    
    
    unique_ptr (const unique_ptr&) = delete;

    可以看到,拷贝操作直接被禁掉了。

    在应用方面,auto_ptr由于奇怪的拷贝语义,导致在容器中使用的话很容易出错,比如下面的代码:

    vector<auto_ptr<int>> foo;
    ...
    auto  item = foo[0];

    容器中的元素不知不觉就被改掉了(置为null)。

    如果是unique_ptr,就看得很清楚了:

    vector<unique_ptr<int>> foo;
    ...
    auto  item = std::move(foo[0]);

    这样也算是更改了容器,但是加上std::move之后(不加会错,因为拷贝被禁用了),代码的意图明显多了。

  • 相关阅读:
    QT Launching Debugger 卡住
    VS无法打开源文件"stdio.h"
    QT 5.15 https 无法访问 TLS initialization failed
    .Net 添加第三方控件
    XML解析——DOM解析
    javascript——对象
    SQL Server 合并表 union 和union all
    深入理解HTTP
    HTTP详解(3)-http1.0 和http1.1 区别
    HTTP详解(2)
  • 原文地址:https://www.cnblogs.com/hustxujinkang/p/5224728.html
Copyright © 2011-2022 走看看