学习笔记八:试图利用C++ Primer 13.5节内容分析shared_ptr指针(共享智能指针)
2015-07-06 15:37
507 查看
C++ Primer 13.5节讲述的是管理类内指针成员的内容。作者分析了采用若采用普通的指针会导致不同对象的指针成员纠缠在一起。这时,作者通过引入一种“使用计数”的方式,介绍了“智能指针”的概念。(当然这里作者只是简单地演示了智能指针的“计数”思想,不过,从这我们也可以一窥共享智能指针shared_ptr的原理)
下面我将书中的例子贴出,并对其进行简单分析。
首先这段代码能够正确执行。实现功能为:初始化类p1,然后利用p1对p2进行复制初始化;之后初始化类p3,并将p3赋值给p2。
智能指针优点:由于采用“使用计数”的思想,所以当某个类的内存被释放,只要U_Ptr类对象的数据成员use!=0,指针共享对象内存就不会被释放,很好地解决了因为内存释放缘故造成的程序崩溃。
原文可能出现了错误:
在原文中对p1类的初始化是这样的:
但是我认为这是错误的,运行示例也证实了我的观点(编译不会出错,但执行时出现致命错误)。
这里,我认为出现这种状况的原因是,我们在定义智能指针时,析构函数中使用了
从这些代码里我们可以看到boost库shared_ptr的影子,它之所以不需要用户delete内存,是因为在类内的析构函数中它已经帮你做啦。不过这也是shared_ptr在初始化是,必须要用new或同类对象初始化的原因(否则new和delete不能配对)。另外,boost使用了保护机制,它不允许share_ptr和普通指针之间的相互复制和赋值,这样可以避免普通指针指向栈内存时,再将其传给shared_ptr后,引起的致命错误(就如上述我们分析的那样)。(当然,关于boost库中的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不能与普通指针相互转化是我个人理解,不确保一定正确)
相关文章推荐
- C++静态成员小结
- C++学习笔记3——类的封装(1)
- C++编程规范 头文件格式 和 函数注释格式
- 【c语言】二维数组中的查找,杨氏矩阵在一个二维数组中,每行都按照从左到右的递增的顺序排序,输入这样的一个数组和一个数,判断数组中是否包含这个数
- 【C语言】二维数组中的查找,杨氏矩阵
- 【学习笔记】【C语言】递归
- C++类型转化:static_cast,reinterpret_cast,dynamic_cast,const_cast
- C++类型转化:static_cast,reinterpret_cast,dynamic_cast,const_cast
- C++ ofstream和ifstream详细用法 及文件操作 导入到EXCEL
- C++笔试题第三波
- 黑马程序员——C语言---预处理指令
- 循环队列的C++实现以及假溢出的解决方法
- C++的异常处理
- C++ Bit Fields
- vc++加载透明png图片方法-GDI+和CImage两种
- C语言入门:03.关键字、标识符、注释
- 《C语言及程序设计》程序阅读——位运算及其应用
- C++编译器符号表有哪些内容?(程序员面试笔试笔记47页提到----符号表)
- c语言位运算有什么作用?
- C语言学习笔记:16_位运算