简单来说,C++智能指针是包含重载运算符的类,其行为像是常规的指针,但智能指针能够及时,妥善地销毁动态分配的数据,并实现了明确的对象生命周期。智能指针的关键在于,重载 引用运算符(*)和成员选择运算符(->).使智能指针真正智能的是复制构造函数、赋值运算符和析构函数的实现。它们决定了智能指针对象被传递给函数、赋值或者离开作用域时的行为。
智能指针最基本的组成部分:
template <typename T>
class smart_pointer
{
private:
T* rawPtr;
public:
smart_pointer (T* pData) : rawPtr (pData) {} // constructor
~smart_pointer () {delete rawPtr;}; // destructor
// copy constructor
smart_pointer (const smart_pointer & anotherSP);
// copy assignment operator
smart_pointer& operator= (const smart_pointer& anotherSP);
T& operator* () const // dereferencing operator
{
return *(rawPtr);
}
T* operator-> () const // member selection operator
{
return rawPtr;
}
};
// empty stub to enable compilation
int main()
{
return 0;
}
智能指针的类型
- 深复制
- 写时拷贝
- 引用计数
- 引用链接
- 破坏性复制
使用深复制的智能指针:
template <typename T>
class deepcopy_smart_ptr
{
private:
T* object;
public:
//... other functions
// copy constructor of the deepcopy pointer
deepcopy_smart_ptr (const deepcopy_smart_ptr& source)
{
// Clone() is virtual: ensures deep copy of Derived class object
object = source->Clone ();
}
// copy assignment operator
deepcopy_smart_ptr& operator= (const deepcopy_smart_ptr& source)
{
if (object)
delete object;
object = source->Clone ();
}
};
// stub to ensure compilation
int main()
{
return 0;
}
我的理解,在多态中简单的值传递可能会导致切除问题,只是保留基类的部分。如果使用的是深复制的智能指针的话,就可以避免此类问题。
改进的情况,写时复制(COW),只有在有人要修改内容的时候,才拷贝出来一份副本出来。而其他指针实例任然共享源对象。
引用计数智能指针
这种智能指针在复制的时候,需要将对象的引用计数加1,一般有两种方法:在对象中维护引用计数;引用计数由共享对象中的指针类维护。注意:在使用智能指针管理对象的同时,让原始指针指向它是一种糟糕的做法。当引用计数减为零的时候而释放对象,原始指针将指向不属于当前应用程序的内存。如果两个引用对象分别存储指向对方的指针,那么这两个对象永远不会被释放。
引用链接智能指针
不主动维护对象的引用计数,而只需要知道计数什么时候变为0,以便释放对象。其实现是基于双向链表的。
破坏性复制
破坏性指针的机制,在智能指针被复制时,将对象的所有权交给目标指针并重置原来的指针。它的一个优点:可以保证任何时刻只有一个活动的指针指向对象。该智能指针的复制构造函数和赋值运算符不能接受const引用,因为它在复制源引用后使其无效了。鉴于这种智能指针销毁源引用,所以不适用于STL容器。
一个破坏性复制智能指针:
template <typename T>
class destructivecopy_ptr
{
private:
T* object;
public:
destructivecopy_ptr(T* input):object(input) {}
~destructivecopy_ptr() { delete object; }
// copy constructor
destructivecopy_ptr(destructivecopy_ptr& source)
{
// Take ownership on copy
object = source.object;
// destroy source
source.object = 0;
}
// copy assignment operator
destructivecopy_ptr& operator= (destructivecopy_ptr& source)
{
if (object != source.object)
{
delete object;
object = source.object;
source.object = 0;
}
}
};
int main()
{
destructivecopy_ptr<int> num (new int);
destructivecopy_ptr<int> copy = num;
// num is now invalid
return 0;
}
使用std::unique_ptr
要使用std:unique_ptr, 必须包含头文件<memory>:
#include <memory>
这是一种简单的智能指针,但其复制构造函数和赋值运算符被声明为私有的,因此不能复制它,即不能将其按值传递给函数,也不能将其赋给其他指针。
#include <iostream>
#include <memory>
using namespace std;
class Fish
{
public:
Fish() {cout << "Fish: Constructed!" << endl;}
~Fish() {cout << "Fish: Destructed!" << endl;}
void Swim() const {cout << "Fish swims in water" << endl;}
};
void MakeFishSwim(const unique_ptr<Fish>& inFish)
{
inFish->Swim();
}
int main()
{
unique_ptr<Fish> smartFish (new Fish);
smartFish->Swim();
MakeFishSwim(smartFish); // OK, as MakeFishSwim accepts reference
unique_ptr<Fish> copySmartFish;
// copySmartFish = smartFish; // error: operator= is private
unique_ptr<Fish> sameFish (std::move(smartFish));
// smartFish is empty henceforth
return 0;
}
编写使用多个线程的应用程序时,可以考虑std::shared_ptr和std::weak_ptr,它们可帮助您实现线程安全和引用计数对象的共享。
有兴趣的同学可以了解下Boost库(www.boost.org)。