智能指针auto_ptr

前奏:

Garbage Collection 技术一直颇受注目,并且在 Java 中已经发展成熟,成为内
存管理的一大利器,但它在 C++ 语言中的发展却不顺利,C++ 为了追求运行速度,20 年来
态度坚决地将其排除在标准之外。

为了稍许平复因为没有 Garbage Collection 而引发的 C++ 程序员的怨气,C++
对 Smart Pointer 技术采取了不同的态度。

首先,了解一下智能指针,

该方法使用一个指针类来代表对资源的管理逻辑,并将指向资源的句柄(指针
或引用)通过构造函数传递给该类。当离开当前范围(scope)时,该对象的析构函数一定会
被调用,所以嵌在析构函数中的资源回收的代码也总是会被执行。这种方法的好处在于,由
于将资源回收的逻辑通过特定的类从原代码中剥离出来,自动正确地销毁动态分配的对象,
这会让思路变得更加清晰,同时确保内存不发生泄露。

它的一种通用实现技术是使用引用计数(Reference Count) 。引用计数智能指针,是一
种生命期受管的对象,其内部有一个引用计数器。当内部引用计数为零时,这些对象会自动
销毁自身的智能指针类。每次创建类的新对象时,会初始化指针并将引用计数置为 1 ;当对
象作为另一对象的副本而创建时,它会调用拷贝构造函数拷贝指针并增加与之相应的引用计
数 ;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数 ;如果引用计数
减至 0,则删除对象,并增加右操作数所指对象的引用计数 ;调用析构函数时,构造函数减
少引用计数,直到计数为 0,释放对象空间。

其次,auto_ptr包含在#include <memory>

auto_ptr 可以指向一个以 new 建立的对象,当 auto_ptr 的生命周期结束时,其所指向的
对象之资源也会被自动释放,且不必显式地调用 delete,而对象指针的操作依旧如故。例如:
class A
{
public:
A(){}
~A(){}
void Hello()

{
std::cout<<"Hello Smart Pointer";
}
};
int main()
{
std::auto_ptr<A> pA(new A());
pA->Hello();
return 0;
}
当然,也可以建立一个未指向任何对象的 auto_prt,例如:
std::auto_ptr<int> iPtr;
它就像空指针,未指向任何对象,所以也就不能进行操作,但是可以通过 get() 函数来
判断它是否指向对象的地址:
if(iPtr.get() == 0) // 不指向任何对象
{
iPtr.reset(new int(2011)); // 指向一个对象
}
auto_ptr 还可以使用另一个 auto_ptr 来建立,但是需要十分小心的是,这会造成所有权
的转移,例如:
auto_ptr< string> sPtr1 (new string("Smart Pointer"));
auto_ptr< string> sPtr2 (sPtr1);
if( !sPtr1->empty() )
cout<<*sPtr1<< endl;
当使用 sPtr1 来建立 sPtr2 时,sPtr1 不再对所指向对象的资源释放负责,而是将接力
棒传递到了 sPtr2 的手里,sPtr1 丧失了使用 string 类成员函数的权利,所以在判断 sPtr1-
>empty() 时程序会崩溃。
auto_ptr 的资源维护动作是以 inline 的方式来完成的,在编译时代码会被扩展开来,所
以使用它并不会牺牲效率。虽然 auto_ptr 指针是一个 RAII (Resource Acquisition In Initialization)对象,能够给我们带来很多便利,
但是它的缺点同样不可小觑:

auto_ptr 对象不可作为 STL 容器的元素,所以二者带来的便利不能同时拥有。这一重
大缺陷让 STL 的忠实拥趸们愤怒不已。
auto_ptr 缺少对动态配置而来的数组的支持,如果用它来管理这些数组,结果是可怕
的、不可预期的。
auto_ptr 在被复制的时候会发生所有权转移。

就在 2011 年的 9 月刚刚获得通过的 C++ 新标
准 C++ 11 中废弃了 auto_ptr 指针,取而代之的是两个新的指针类:shared_ptr 和 unique_ptr。
shared_ptr 只是单纯的引用计数指针,unique_ptr 是用来取代 auto_ptr 的。unique_ptr 提供了
auto_ptr 的大部分特性,唯一的例外是 auto_ptr 的不安全、隐性的左值搬移 ;而 unique_ptr
可以存放在 C++0x 提出的那些能察觉搬移动作的容器之中。

在 Boost 中的智能指针共有五种 :scoped_ptr、scoped_array、shared_ptr、shared_array、
weak_ptr,其中最有用的就是 shared_ptr,它采取了引用计数,并且是线程安全的,同时支
持扩展,推荐在大多数情况下使用。

boost::shared_ptr 支持 STL 容器:
typedef boost::shared_ptr<string> CStringPtr;
std::vector< CStringPtr > strVec;
strVec.push_back( CStringPtr(new string("Hello")) );

当 vector 被销毁时,其元素 — 智能指针对象才会被销毁,除非这个对象被其他的智能
指针引用,如下面的代码片段所示:
typedef boost::shared_ptr<string> CStringPtr;
std::vector< CStringPtr > strVec;
strVec.push_back( CStringPtr(new string("Hello")) );
strVec.push_back( CStringPtr(new string("Smart")) );
strVec.push_back( CStringPtr(new string("Pointer")) );
CStringPtr strPtr = strVec[0];
strVec.clear(); //strVec 清空,但是保留了 strPtr 引用的 strVec[0]
cout<<*strPtr<<endl; // strVec[0] 依然有效

Boost 智能指针同样支持数组,boost::scoped_array 和 boost::shared_array 对象指向的是
动态配置的数组。
Boost 的智能指针虽然增强了安全性,处理了潜在的危险,但是我们在使用时还是应该
遵守一定的规则,以确保代码更加鲁棒。

规则 1:Smart_ptr<T> 不同于 T*
Smart_ptr<T> 的真实身份其实是一个对象,一个管理动态配置对象的对象,而 T* 是指
向 T 类型对象的一个指针,所以不能盲目地将一个 T* 和一个智能指针类型 Smart_ptr<T> 相
互转换。
在创建一个智能指针的时候需要明确写出 Smart_ptr<T> tPtr<new T>。
禁止将 T* 赋值给一个智能指针。

不能采用 tPtr = NULL 的方式将 tPtr 置空,应该使用智能指针类的成员函数。

规则 2:不要使用临时的 share_ptr 对象

class A;
bool IsAllReady();
void ProcessObject(boost::shared_ptr< A> pA, bool isReady);
ProcessObject(boost::shared_ptr(new A), IsAllReady());
调用 ProcessObject 函数之前,C++ 编译器必须完成三件事:
(1) 执行 "new A"。
(2) 调用 boost::shared_ptr 的构造函数。
(3) 调用函数 IsAllReady()。
因为函数参数求值顺序的不确定性,如果调用 IsAllReady() 发生在另外两个过程中间,
而它又正好出现了异常,那么 new A 得到的内存返回的指针就会丢失,进而发生内存泄露,
因为返回的指针没有被存入我们期望能阻止资源泄漏的 boost::shared_ptr 上。避免出现这种
问题的方式就是不要使用临时的 share_ptr 对象,改用一个局部变量来实现,在一个独立的语
句中将通过 new 创建出来的对象存入智能指针中:

boost::shared_ptr<A> pA(new A)
ProcessObject(pA, IsAllReady());
如果疏忽了这一点,当异常发生时,可能会引起微妙的资源泄漏。

时间: 2024-11-08 23:41:50

智能指针auto_ptr的相关文章

智能指针auto_ptr详解

概述:C++中有很多种智能指针,auto_ptr就是其中的一种,该智能指针主要是为了解决"因程序异常退出发生的内存泄漏"这类问题的. 我们先来看下面的问题代码 #include<iostream> #include<memory> #include<exception> using namespace std; //一般指针的处理方式 template<typename T> class OldClass { public: OldCla

C++中的智能指针(auto_ptr)

实际上auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是完全完美的. 本文从下面的8个方面来总结auto_ptr使用的大部分内容. 1. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个这样拥有者(auto_ptr).当auto_ptr对象生命

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

【C++智能指针 auto_ptr】

<More Effective C++>ITEM M9中提到了auto_ptr,说是当异常产生的时候,怎么释放为对象分配的堆内存,避免重复编写内存释放语句. PS:这里书里面提到函数退出问题,函数退出会清理栈内存,不管是怎么正常退出还是异常退出(仅有一种例外就是当你调用 longjmp 时.Longjmp 的这个缺点是 C++率先支持异常处理的主要原因).建立在此基础上我们才把对指针的删除操作封装到一个栈对象里面.这样函数退出(异常或是正常)就会调用对象的析构函数,达到我们自动清理所封装指针指

C++智能指针 auto_ptr

C++智能指针 auto_ptr auto_ptr 是一个轻量级的智能指针, 定义于 memory (非memory.h)中, 命名空间为 std. auto_ptr 适合用来管理生命周期比较短或者不会被远距离传递的动态对象, 最好是局限于某个函数内部或者是某个类的内部. 使用方法: std::auto_ptr<int> pt(new int(10)); pt.reset(new int(11)); 成员函数 3个重要的函数: (1) get 获得内部对象的指针, 由于已经重载了()方法, 因

C++智能指针--auto_ptr指针

auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放.即使发生异常,通过异常的栈展开过程也能将动态内存释放.auto_ptr不支持new数组. auto_ptr的出现,主要是为了解决"有异常抛出时发生内存泄漏"的问题.如下的简单代码是这类问题的一个简单示

C++ 智能指针auto_ptr详解

1. auto_ptr 的设计动机: 函数操作经常依照下列模式进行: 获取一些资源 执行一些动作 释放所获取的资源 那么面对这些资源的释放问题就会出现下面的两种情况: 一开始获得的资源被绑定于局部对象,那么当函数退出的时候,这些局部对象的析构函数被自动的调用,从而自动释放掉这些资源; 一开始获得的资源是通过某种显示手段获取,而且并没有绑定在任何对象身上,那么必须以显式的方式释放.这种情况常常发生在指针身上; 例子: 1 void f() 2 { 3 ClassA* ptr = new Class

【C++】智能指针auto_ptr的简单实现

//[C++]智能指针auto_ptr的简单实现 #include <iostream> using namespace std; template <class _Ty> class auto_ptr { public: auto_ptr(_Ty *_P = 0) :_Owns(_Ptr != 0), _Ptr(_P) {} auto_ptr<_Ty>(const auto_ptr <_Ty> &p):_Owns(p._Owns),_Ptr(p.r

智能指针auto_ptr源码剖析

何时我们需要智能指针? 资源所有权的共享 共享所有权是指两个或多个对象需要同时使用第三个对象的情况.这第三个对象应该如何(或者说何时)被释放?为了确保释放的时机是正确的,每个使用这个共享资源的对象必须互相知道对方,才能准确掌握资源的释放时间.从设计或维护的观点来看,这种耦合是不可行的.更好的方法是让这些资源所有者将资源的生存期管理责任委派给一个智能指针.当没有共享者存在时,智能指针就可以安全地释放这个资源了. 要编写异常安全的代码时 异常安全简单地说就是在异常抛出时没有资源泄漏并保证程序状态的一

C/C++——跟我重写智能指针auto_ptr模版类

第一次使用auto_ptr的时候感觉很好用,但是对内部原理根本不懂,心里不知道这东西到底是个什么东东,总是感觉这东东比较陌生.今天有时间来简单实现一下该类模版auto_ptr,实现了该模版类的主要功能,可以让大家了解一下这个东东内部到底是个什么情况. 栈对象和堆对象的区别: 首先,看一下两种类对象的区别,一个是在栈上分配空间,另一个是在堆上分配空间. 如果看到这里,你不清楚堆和栈的区别.那我也不解释了,自行Google..(如果你想baidu也不拦你) 1.先测试栈上分配的对象 #include