一个引用计数的智能指针,但总觉得有不好的地方

前景:
造成内存泄露的大多原因都是因为分配了空间但是没有进行释放的结果。但是这样并不会引发错误
一般来说,解决这个问题的有很多种方法,比如com、boost的智能指针,都在某一种情况下对这种问题提供了解决方案。下面来探讨两种情况的指针

但我们可以建立一个自己的smart point,同时也需要考虑三种情况:
是否允许对smart point进行复制,如果是,在smart point中的多份拷贝中,到底有哪一个负责删除它们共同指向的对象(com是最后一个)
smart point是否表示指向一个对象的指针,或者表示指向一个对象数组的指针(即它应该使用带方括号的还是不带方括号的delete操作符)
smart point是否对应于一个常量指针或一个非常量指针

出于上述的三个情况,有以下两种smart point可以满足:
1.引用计数指针(又称共享指针,也就是com中的smart point)
2.作用域指针
这两种smart point的不同之处在于引用计数指针可以被复制,而作用域指针不能被复制。但是,作用域指针的效率更高。

引用计数指针的一个例子:


#ifndef __SCCP_SCOPEDPTR_H__
#define __SCCP_SCOPEDPTR_H__

namespace scpp
{
template <typename T>
class RefCountPtr
{
public:
explicit RefCountPtr(T* p = NULL)
{
Create(p);
}

RefCountPtr(const RefCountPtr<T>& rhs)
{
Copy(rhs);
}

RefCountPtr<T>& operator = (const RefCountPtr<T>& rhs)
{
if (ptr_ != rhs.ptr_)
{
Kill();
Copy(rhs);
}

return *this;
}

RefCountPtr<T>& operator = (T *p)
{
if (ptr_ != p)
{
Kill();
Create(p);
}

return *this;
}

~RefCountPtr()
{
std::cout << "kill" << std::endl;
Kill();
}

public:
T* Get() const { return ptr_; }

T* operator ->() const
{
std::cout << "in this" << std::endl;
return ptr_;
}

T& operator *() const
{
return *ptr_;
}

private:
void Create(T* p)
{
ptr_ = p;
if (ptr_ != NULL)
{
refCount_ = new int;
*refCount_ = 1;
}
else
{
refCount_ = NULL;
}
}

void Copy(const RefCountPtr<T>& rhs)
{
ptr_ = rhs.ptr_;
refCount_ = rhs.refCount_;
if (refCount_ != NULL)
{
++(*refCount_);
}
}

void Kill()
{
if (refCount_ != NULL)
{
if (--(*refCount_) == 0)
{
delete ptr_;
ptr_ = NULL;
delete refCount_;
refCount_ = NULL;
}
}
}
private:
T* ptr_;
int* refCount_;
};
} // namespace scpp

#endif // __SCCP_SCOPEDPTR_H__


测试demo是这样的:

// debug.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
#include "scpp_refcountptr.h"

class Student
{
public:
Student(int age) : age_(age)
{
}
void ShowAge()
{
std::cout << "my age is : " << age_ << std::endl;
}
private:
int age_;
};

int _tmain(int argc, _TCHAR* argv[])
{
scpp::RefCountPtr<Student> smartPoint(new Student(10));
scpp::RefCountPtr<Student> smartPoint2;

smartPoint2 = smartPoint; //@test:赋值操作符
smartPoint = NULL;
smartPoint2->ShowAge();

scpp::RefCountPtr<Student> smartPoint3(smartPoint2); //@test:拷贝构造函数
smartPoint2 = NULL;
smartPoint3->ShowAge();

scpp::RefCountPtr<Student> *smartPoint4; //@test:引用
smartPoint4 = &smartPoint3;
smartPoint4->Get()->ShowAge();

Student studen3 = *smartPoint3; //@test:Get()
studen3.ShowAge();
smartPoint3 = NULL;

return 0;
}


我总是有一种感觉,好像有什么不妙的地方。。大家来讨论讨论
...全文
456 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
healer_kx 2013-02-25
  • 打赏
  • 举报
回复
引用 15 楼 zhao4zhong1 的回复:
就算引用计数完美解决了内存资源泄漏问题,还有很多其它资源的泄漏问题等着操作系统或应用软件的设计者去解决。比如:句柄、线程、USER对象、GDI对象、Socket连接、USB设备、打印机设备、……
这是一句废话。。。 引用计数,GC都不是处理OS问题的办法,这样都太慢了。
qingcairousi 2013-02-25
  • 打赏
  • 举报
回复
引用 15 楼 zhao4zhong1 的回复:
就算引用计数完美解决了内存资源泄漏问题,还有很多其它资源的泄漏问题等着操作系统或应用软件的设计者去解决。比如:句柄、线程、USER对象、GDI对象、Socket连接、USB设备、打印机设备、……
我猜你一定不知道什么叫RAII,更没有用过RAII。 引用计数如果不是有RAII的话,没太大优点,只有加上RAII的引用计数才是真正有意义的。
赵4老师 2013-02-25
  • 打赏
  • 举报
回复
就算引用计数完美解决了内存资源泄漏问题,还有很多其它资源的泄漏问题等着操作系统或应用软件的设计者去解决。比如:句柄、线程、USER对象、GDI对象、Socket连接、USB设备、打印机设备、……
healer_kx 2013-02-24
  • 打赏
  • 举报
回复
我觉得有点问题 1. 释放对象用delete,这种假设不好。释放对象,可能是free的,可能是delete[],也有可能是其他方式,也有可能是delete,但是链接到其他CRT的。 优点是 对对象来说,引用计数是非侵入式的。
healer_kx 2013-02-24
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
不要企图优雅的结束(因为这是不可能办到的) 而要在烂的不能再烂的摊子上也能重整河山!
复杂的C代码也是用引用计数的,比如Python解释器。
太上绝情 2013-02-24
  • 打赏
  • 举报
回复
引用计数就怕互相引用,学习java用连通图吧,就是效率别想要了
billzheng 2013-02-23
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
不要企图优雅的结束(因为这是不可能办到的) 而要在烂的不能再烂的摊子上也能重整河山!
这条狗,满嘴狗屎! 你不喜欢C++别来C++论坛,你来一次我骂你一次。
linyilong3 2013-02-23
  • 打赏
  • 举报
回复
引用 1 楼 QQ1507527443 的回复:
你这多线程必挂。看看atl的实现,会有参考价值的。
多线程的问题应该留给使用者去解决,BOOST也没见过有加锁
  • 打赏
  • 举报
回复
有一本书,叫做垃圾收集的,里面有描述楼主想要的东西
赵4老师 2013-01-07
  • 打赏
  • 举报
回复
不要企图优雅的结束(因为这是不可能办到的) 而要在烂的不能再烂的摊子上也能重整河山!
ri_aje 2013-01-07
  • 打赏
  • 举报
回复
引用 6 楼 zengraoli 的回复:
引用 4 楼 ri_aje 的回复:不知道这算不算一个问题。 C/C++ code?1scpp::RefCountPtr<Student>(new Student [10]); // undefined behavior in Kill, at best memory leak. 这问题只出在Student的测试类上面,private封掉他的默认构造就行了,感谢指出,……
我咋觉得你没理解我的话呢。我说的是 Kill 里面写死了通过 delete 释放资源,后者用于处理 new 数组的时候会导致 UB,此问题和测试类无关。
  • 打赏
  • 举报
回复
引用 4 楼 ri_aje 的回复:
不知道这算不算一个问题。 C/C++ code?1scpp::RefCountPtr<Student>(new Student [10]); // undefined behavior in Kill, at best memory leak.
这问题只出在Student的测试类上面,private封掉他的默认构造就行了,感谢指出,没想到会在测试类上面出现小问题 呵呵
ri_aje 2013-01-07
  • 打赏
  • 举报
回复
当然 Student 得修改一下支持默认构造,不过这不是重点。
ri_aje 2013-01-07
  • 打赏
  • 举报
回复
不知道这算不算一个问题。

scpp::RefCountPtr<Student>(new Student [10]); // undefined behavior in Kill, at best memory leak.
  • 打赏
  • 举报
回复
引用 1 楼 QQ1507527443 的回复:
你这多线程必挂。看看atl的实现,会有参考价值的。
后面慢慢完善嘛,这边我看着好像都有问题
  • 打赏
  • 举报
回复
引用 1 楼 QQ1507527443 的回复:
你这多线程必挂。看看atl的实现,会有参考价值的。
多线程这个好处理,加个异步锁就行
搞笑的程序员 2013-01-06
  • 打赏
  • 举报
回复
你这多线程必挂。看看atl的实现,会有参考价值的。

64,636

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧