进入函数foo 退出函数
| A
V |
auto_ptr<string>::auto<string>() auto_ptr<string>::~auto_ptr<string>()
| A
V |
string::string() string::~string()
| A
V |
_data=new char[] delete [] _data
| A
V |
使用资源 -----------------------------------> 释放资源
现在我们拥有了最简单的垃圾回收机制(我隐瞒了一点,在string中,你仍然需要自己编码控制对象的动态创建和销毁,但是这种情况下的准则极其简单,就是在构造函数中分配资源,在析构函数中释放资源,就好像飞机驾驶员必须在起飞后和降落前检查起落架一样。),即使在foo函数中发生了异常,str的生存期也会结束,C++保证自然退出时发生的一切在异常发生时一样会有效。
auto_ptr<>只是智能指针的一种,它的复制行为提供了所有权转移的语义,即智能指针在复制时将对内部维护的实际指针的所有权进行了转移,例如
auto_ptr < string > str1( new string( < str1 > ) );
cout << str1->c_str();
auto_ptr < string > str2(str1); // str1内部指针不再指向原来的对象
cout << str2->c_str();
cout << str1->c_str(); // 未定义,str1内部指针不再有效
某些时候,需要共享同一个对象,此时auto_ptr就不敷使用,由于某些历史的原因,C++的标准库中并没有提供其他形式的智能指针,走投无路了吗?
另一种智能指针
但是我们可以自己制作另一种形式的智能指针,也就是具有值复制语义的,并且共享值的智能指针。
需要同一个类的多个对象同时拥有一个对象的拷贝时,我们可以使用引用计数(Reference Counting/Using Counting)来实现,曾经这是一个C++中为了提高效率与COW(copy on write,改写时复制)技术一起被广泛使用的技术,后来证明在多线程应用中,COW为了保证行为的正确反而导致了效率降低(Herb Shutter的在C++ Report杂志中的Guru专栏以及整理后出版的《More Exceptional C++》中专门讨论了这个问题)。
然而对于我们目前的问题,引用计数本身并不会有太大的问题,因为没有牵涉到复制问题,为了保证多线程环境下的正确,并不需要过多的效率牺牲,但是为了简化问题,这里忽略了对于多线程安全的考虑。
首先我们仿造auto_ptr设计了一个类模板(出自Herb Shutter的《More Execptional C++》),
template < typename T >
class shared_ptr
{
private:
class implement // 实现类,引用计数
{
public:
implement(T* pp):p(pp),refs(1){}
~implement(){delete p;}
T* p; // 实际指针
size_t refs; // 引用计数
};
implement* _impl;
public:
explicit shared_ptr(T* p)
: _impl(new implement(p)){}
~shared_ptr()
{
decrease(); // 计数递减
}
shared_ptr(const shared_ptr& rhs)
: _impl(rhs._impl)
{
increase(); // 计数递增
}
shared_ptr& operator=(const shared_ptr& rhs)
{
if (_impl != rhs._impl) // 避免自赋值
{
decrease(); // 计数递减,不再共享原对象
_impl=rhs._impl; // 共享新的对象
increase(); // 计数递增,维护正确的引用计数值
}
return *this;
}
T* operator->() const
{
return _impl->p;
}
T& operator*() const
{
return *(_impl->p);
}
private:
void decrease()
{
if (--(_impl->refs)==0)
{ // 不再被共享,销毁对象
delete _impl;
}
}
void increase()
{
++(_impl->refs);
}
};










