智能指针是对指针进行一次封装,让指针变得更加智能,更易于管理。
首先了解一下封装指针的几种情况:
(1)采购拷贝的方式。这样的指针对象既负责创建数据对象,又负责删除数据对象,STL容器对象采用的就是这种方式。采用这种方式的指针对
象责任最清晰。可以参考一下std::vector的C++ Reference文档
public member function
vector::vector
<vector>
explicit vector ( const Allocator& = Allocator() );
explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );
template <class InputIterator>
vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
vector ( const vector<T,Allocator>& x );
Construct vector
Constructs a vector container object, initializing its contents depending on the constructor version used:-
explicit vector ( const Allocator& = Allocator() );
- Default constructor: constructs an empty vector, with no content and a size of zero. explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );
- Repetitive sequence constructor: Initializes the vector with its content set to a repetition, n times, of copies of value. template <class InputIterator> vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
- Iteration constructor: Iterates between first and last, setting a copy of each of the sequence of elements as the content of the container. vector ( const vector<T,Allocator>& x );
- Copy constructor: The vector is initialized to have the same contents (copies) and properties as vector x.
public member function
vector::~vector
~vector ( );
Vector destructor
Destructs the container object. This calls each of the contained element's destructors, and deallocates all the storage capacity allocated by the vector.
(2)采用完全接管的方式,指针对象不负责创建数据对象,但是负责删除数据对象。既不仅接管了源指针指向的对象,还接管了指针指向对象的所有权。auto_ptr<>就是采用这种方式实现的。
(3)采用接管的方式,既不负责创建数据对象,也不负责删除数据对象。STL中的迭代器(iterator)采用的就是这种方式。
(4)完全接管和深层拷贝方式相结合。一般的情况是:拷贝构造和拷贝赋值采用深拷贝方式,而指针构造和指针赋值采用接管方式。这种方式最容易产生运行时内存访问冲突和内存泄露问题,不建议使用。
模拟泛型指针:auto_ptr 采用完全接管的方式。
template
<
typename
T
>
class
auto_ptr
{
public
:
auto_ptr(
T
*p = NULL):
m_ptr
(p){}
auto_ptr<T>& operator = (const auto_ptr <T>& ptr) {
if(&ptr != this) {
delete m_ptr ;
m_ptr = ptr.release(); //释放并移交拥有权,修改了实参对象。
}
return *this ;
}
~auto_ptr(){
delete
m_ptr
;
}
T
* release()
const
{
T
* tem =
m_ptr
;
((
auto_ptr
<
T
>*)
this
)->
m_ptr
= 0;
return
tem;
}
T& operator *() {
return
*
m_ptr
;
}
T
* operator ->() {
return
m_ptr
;
}
private
:
T
*
m_ptr
;
};
struct A {
public:
A(){}
A(int num,char ch): m_num(num), m_ch(ch){}
int m_num ;
char m_ch ;
};
int main( void) {
A* a = new A(1,'a');
auto_ptr
<
A
> aPtr(a);
auto_ptr
<
A
> bPtr(aPtr);
std ::cout<<aPtr->
m_ch
<<std ::
endl
; //运行出错因为aPtr已经把指针a的所有权转交给bPtr,把自己的m_ptr设为控指针了。
//delete a 不需要我们去释放a所指向内存空间了。
return 0;
}
auto_ptr<>采用完全接管的方式,使用auto_ptr<>的好处是:当函数推出时,C++保证会在堆栈清退的过程中自动调用每一个局部对象的析构函数。当调用auto_ptr<>的析构函数时,我们释放了指针所指向的对象空间。
auto_ptr<>不适合作为STL容器的元素类型:
因为auto_ptr的特点是接管和转移拥有权,因此,auto_ptr对象和它的拷贝不会共享实值对象。然而根据STL容器“值”语义的要求,可拷贝构造意味着一个对象必须和它的拷贝相同。
例如:
std::vector<auto_ptr<A> > v;
v.push_back(aPtr);
auto_ptr<A> tem = v.front(); //这里改变了容器的元素
所以不要使用容器来装载auto_ptr指针对象。