您的位置:首页 > 编程语言 > C语言/C++

学习笔记八:试图利用C++ Primer 13.5节内容分析shared_ptr指针(共享智能指针)

2015-07-06 15:37 507 查看
C++ Primer 13.5节讲述的是管理类内指针成员的内容。作者分析了采用若采用普通的指针会导致不同对象的指针成员纠缠在一起。这时,作者通过引入一种“使用计数”的方式,介绍了“智能指针”的概念。(当然这里作者只是简单地演示了智能指针的“计数”思想,不过,从这我们也可以一窥共享智能指针shared_ptr的原理)

下面我将书中的例子贴出,并对其进行简单分析。

#include <iostream>

using namespace std;

// private class for use by HasPtr only
class U_Ptr {
friend class HasPtr;
int *ip;
size_t use;
U_Ptr(int *p): ip(p), use(1) { }
~U_Ptr()
{
delete ip;
}
};

/* smart pointer class: takes ownership of the dynamically allocated
*          object to which it is bound
* User code must dynamically allocate an object to initialize a HasPtr
* and must not delete that object; the HasPtr class will delete it
*/
class HasPtr {
public:
// HasPtr owns the pointer; pmust have been dynamically allocated
HasPtr(int *p, int i): ptr(new U_Ptr(p)), val(i)
{ }

// copy members and increment the use count
HasPtr(const HasPtr &orig):
ptr(orig.ptr), val(orig.val)
{
++ptr->use;
}
HasPtr& operator=(const HasPtr&);

// if use count goes to zero, delete the U_Ptr object
~HasPtr()
{
if (--ptr->use == 0)
delete ptr;
}

int *get_ptr() const { return ptr->ip; }
int get_int() const { return val; }

// change the appropriate data member
void set_ptr(int *p) { ptr->ip = p; }
void set_int(int i) { val = i; }

// return or change the value pointed to, so ok for const objects
// Note: *ptr->ip is equivalent to *(ptr->ip)
int get_ptr_val() const { return *ptr->ip; }
void set_ptr_val(int i) { *ptr->ip = i; }

private:
U_Ptr *ptr;        // points to use-counted U_Ptr class
int val;
};

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
++rhs.ptr->use;     // increment use count on rhs first
if (--ptr->use == 0)
delete ptr;    // if use count goes to 0 on this object, delete it
ptr = rhs.ptr;      // copy the U_Ptr object
val = rhs.val;      // copy the int member
return *this;
}

int main()
{
/*int obj = 0;
HasPtr p1(&obj, 42);*/
int *p_int = new int(0);
HasPtr p1(p_int, 42);
HasPtr p2(p1);
int *p_int1 = new int(10);
HasPtr p3(p_int1,43);
p2 = p3;

return 0;
}


首先这段代码能够正确执行。实现功能为:初始化类p1,然后利用p1对p2进行复制初始化;之后初始化类p3,并将p3赋值给p2。

智能指针优点:由于采用“使用计数”的思想,所以当某个类的内存被释放,只要U_Ptr类对象的数据成员use!=0,指针共享对象内存就不会被释放,很好地解决了因为内存释放缘故造成的程序崩溃。

原文可能出现了错误:

在原文中对p1类的初始化是这样的:

int obj = 0;
HasPtr p1(&obj, 42);


但是我认为这是错误的,运行示例也证实了我的观点(编译不会出错,但执行时出现致命错误)。

这里,我认为出现这种状况的原因是,我们在定义智能指针时,析构函数中使用了
delete p;
命令,这样注定了p只能指向堆内存(栈内存不能执行delete命令),且之前肯定要使用new命令分配一块内存。但是上述代码段却将存在于栈内存中的obj的地址赋给ptr,所以在执行U_Ptr的析构命令时,出现错误。其正确写法应该为:

int *p_int = new int(0);
HasPtr p1(p_int, 42);


从这些代码里我们可以看到boost库shared_ptr的影子,它之所以不需要用户delete内存,是因为在类内的析构函数中它已经帮你做啦。不过这也是shared_ptr在初始化是,必须要用new或同类对象初始化的原因(否则new和delete不能配对)。另外,boost使用了保护机制,它不允许share_ptr和普通指针之间的相互复制和赋值,这样可以避免普通指针指向栈内存时,再将其传给shared_ptr后,引起的致命错误(就如上述我们分析的那样)。(当然,关于boost库中的shared_ptr不能与普通指针相互转化是我个人理解,不确保一定正确)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: