auto_ptr在stl使用中的問題

auto_ptr說明:
C++的auto_ptr所做的事情,就是動態分配對象以及當對象不再需要時自動執行清理。
使用std::auto_ptr,要#include <memory>。
auto_ptr作用:

c++中可以通過auto_ptr實現對內存的管理,當auto_ptr綁定指針後,在auto_ptr結束的時候釋放地址所指向的內存

關於STL中使用auto_ptr的問題:

我們通過一段代碼來觀察:

#include <memory>
#include <iostream>
#include <vector>
using namespace std;


int main()
{
    vector<auto_ptr<int>> v(10);
    for(int i=0;i<10;i++)
    {
         v[i] = auto_ptr<int>(new int(1));
    }
    for(int i=0;i<10;i++)
    {
         cout<<*v[i]<<endl;
    }
    return 0;
}

查看網上說auto_ptr不能再stl中使用,但是在vs2017編寫代碼並編譯運行是沒有問題的,所以又在網上查找發現不能運行的挺多的,後來在linux下編譯運行:

g++ auto_ptr.cpp

發現編譯不能通過

auto_ptr.cpp: In function ‘int main()’:
auto_ptr.cpp:9:24: error: ‘>>’ should be ‘> >’ within a nested template argument list
     vector<auto_ptr<int>> v(10);
                        ^
In file included from /usr/include/c++/5/memory:64:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, const _T2&) [with _T1 = std::auto_ptr<int>; _T2 = std::auto_ptr<int>]’:
/usr/include/c++/5/bits/stl_uninitialized.h:202:18:   required from ‘static _ForwardIterator std::__uninitialized_fill_n<_TrivialValueType>::__uninit_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::auto_ptr<int>*; _Size = long unsigned int; _Tp = std::auto_ptr<int>; bool _TrivialValueType = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:247:17:   required from ‘_ForwardIterator std::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::auto_ptr<int>*; _Size = long unsigned int; _Tp = std::auto_ptr<int>]’
/usr/include/c++/5/bits/stl_uninitialized.h:358:39:   required from ‘_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, std::allocator<_Tp2>&) [with _ForwardIterator = std::auto_ptr<int>*; _Size = long unsigned int; _Tp = std::auto_ptr<int>; _Tp2 = std::auto_ptr<int>]’
/usr/include/c++/5/bits/stl_vector.h:1301:33:   required from ‘void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::auto_ptr<int>; _Alloc = std::allocator<std::auto_ptr<int> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::auto_ptr<int>]’
/usr/include/c++/5/bits/stl_vector.h:306:27:   required from ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::auto_ptr<int>; _Alloc = std::allocator<std::auto_ptr<int> >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::auto_ptr<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<std::auto_ptr<int> >]’
auto_ptr.cpp:9:31:   required from here
/usr/include/c++/5/bits/stl_construct.h:83:7: error: no matching function for call to ‘std::auto_ptr<int>::auto_ptr(const std::auto_ptr<int>&)’
       ::new(static_cast<void*>(__p)) _T1(__value);
       ^
In file included from /usr/include/c++/5/memory:88:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/backward/auto_ptr.h:260:7: note: candidate: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr_ref<_Tp>) [with _Tp = int]
       auto_ptr(auto_ptr_ref<element_type> __ref) throw()
       ^
/usr/include/c++/5/backward/auto_ptr.h:260:7: note:   no known conversion for argument 1 from ‘const std::auto_ptr<int>’ to ‘std::auto_ptr_ref<int>’
/usr/include/c++/5/backward/auto_ptr.h:125:9: note: candidate: template<class _Tp1> std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr<_Tp1>&)
         auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }
         ^
/usr/include/c++/5/backward/auto_ptr.h:125:9: note:   template argument deduction/substitution failed:
In file included from /usr/include/c++/5/memory:64:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/bits/stl_construct.h:83:7: note:   types ‘std::auto_ptr<_Tp1>’ and ‘const std::auto_ptr<int>’ have incompatible cv-qualifiers
       ::new(static_cast<void*>(__p)) _T1(__value);
       ^
In file included from /usr/include/c++/5/memory:88:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/backward/auto_ptr.h:112:7: note: candidate: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr<_Tp>&) [with _Tp = int] <near match>
       auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
       ^
/usr/include/c++/5/backward/auto_ptr.h:112:7: note:   conversion of argument 1 would be ill-formed:
In file included from /usr/include/c++/5/memory:64:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/bits/stl_construct.h:83:7: error: binding ‘const std::auto_ptr<int>’ to reference of type ‘std::auto_ptr<int>&’ discards qualifiers
       ::new(static_cast<void*>(__p)) _T1(__value);
       ^
In file included from /usr/include/c++/5/memory:88:0,
                 from auto_ptr.cpp:1:
/usr/include/c++/5/backward/auto_ptr.h:103:7: note: candidate: std::auto_ptr<_Tp>::auto_ptr(std::auto_ptr<_Tp>::element_type*) [with _Tp = int; std::auto_ptr<_Tp>::element_type = int]
       auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
       ^
/usr/include/c++/5/backward/auto_ptr.h:103:7: note:   no known conversion for argument 1 from ‘const std::auto_ptr<int>’ to ‘std::auto_ptr<int>::element_type* {aka int*}’

後來想了一下是不是和編譯條件有關係,添加 -std=c++11編譯通過:

g++ auto_ptr.cpp -std=c++11

執行:

./a.out

結果:

1
1
1
1
1
1
1
1
1
1

通過測試我們可以發現其實只要指定編譯是用c++11標準編譯就可以通過,說明auto_ptr在c++11和之前的實現是不一樣的。
c++標準規定STL元素必須是“可複製構造的”和“可分配的”。換句話說,必須能夠分配或複製一個元素,並且這兩個元素在邏輯上是獨立的。C++11之前的std: auto_ptr 得實現是不滿足此要求。但是auto_ptr是不支持多個auto_ptr指向同一塊內存的,所以在執行=和copy操作時會把原先的auto_ptr指向空。
然而STL容器在分配內存的時候,必須要能夠拷貝構造容器的元素。而且拷貝構造的時候,不能修改原來元素的值。而auto_ptr在拷貝構造的時候,一定會修改元素的值。所以STL元素不能使用auto_ptr。
所以我們可以大膽的猜測c++11中對auto_ptr的拷貝和=重載做了不同的實現,目前博主還不是太清楚。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章