提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
1.shared_ptr的缺点
如果std::shared_ptr仔细考虑,您仍然会发现仍然存在无法释放资源的问题。看下面的例子
#include <mcheck.h> //内存泄露检测工具
#include <iostream>
#include <memory>
class A;
class B;
class A{
public:
std::shared_ptr<B> pointer;
~A() {
std::cout << "A was destroyed" << std::endl;
}
};
class B{
public:
std::shared_ptr<A> pointer;
~B() {
std::cout << "B was destroyed" << std::endl;
}
};
int main() {
setenv("MALLOC_TRACE", "m.log", 1);
mtrace();
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->pointer = b;
b->pointer = a;
return 0;
}
Memory not freed:
Address Size Caller
0x0000000000b84370 0x20 at 0x7f6e26ecee78
0x0000000000b843a0 0x20 at 0x7f6e26ecee78
原因:这两块内存均由A(B)指针和B(A)的成员指针所指向,A和B析构后,堆上成员指针和内存依然相互依存,造成内存泄露。
解决方法:使用弱引用weak_ptr,弱引用不会引起计数器计数。
2.简单实现
代码如下(示例):
#include <iostream>
using namespace std;
template <typename T>
class weak_ptr;
class Count {
public:
int s;
int w;
Count() : s(0), w(0){};
~Count(){};
};
template <typename T>
class smartptr {
public:
//类初始化
smartptr(T* p = nullptr) : ptr_(p) {
cnt_ = new Count();
if (p)
cnt_->s = 1;
}
~smartptr() {
del();
}
//smartptr拷贝构造函数 count.s++
smartptr(const smartptr<T>& orig) : ptr_(orig.ptr_), cnt_(orig.cnt_) {
cnt_->s++;
}
smartptr<T> operator=(const smartptr<T>& orig) {
if (this != &orig) {
del();
ptr_ = orig.ptr_;
cnt_ = orig.cnt_;
cnt_->s++;
}
return orig;
}
int use_count() {
return cnt_->s;
}
T* operator->() {
return ptr_;
}
T& operator*() {
return *ptr_;
}
T* get() {
return ptr_;
}
friend class weak_ptr<T>;
private:
T* ptr_;
//堆上方便共享
Count* cnt_;
void del() {
cnt_->s--;
if (cnt_->s == 0) {
delete ptr_;
ptr_ = nullptr;
if (cnt_->w == 0) {
delete cnt_;
cnt_ = nullptr;
}
}
}
};
template <typename T>
class weak_ptr {
public:
weak_ptr(smartptr<T>& s) : ptr_(s.ptr_), cnt_(s.cnt_) {
if (ptr_ != s.ptr_)
cnt_->w++;
}
weak_ptr(weak_ptr<T>& s) : ptr_(s.ptr_), cnt_(s.cnt_) {
if (ptr_ != s.ptr_)
cnt_->w++;
}
weak_ptr<T>& operator=(smartptr<T>& s){
if(ptr_!=s.ptr_){
del();
cnt_ = s.cnt_;
cnt_->w++;
}
return *this;
}
weak_ptr<T>& operator=(weak_ptr<T>& w){
if(ptr_!=w.ptr_){
del();
cnt_ = w.cnt_;
cnt_->w++;
}
return w;
}
~weak_ptr() {
del();
}
private:
T* ptr_;
Count* cnt_;
void del() {
if (cnt_) {
cnt_->w--;
if (cnt_->w == 0 && cnt_->s == 0)
cnt_ = nullptr;
}
}
};
int main() {
smartptr<int> p1(new int(0));
cout << p1.use_count() << endl;
smartptr<int> p2(p1);
cout << p2.use_count() << endl;
smartptr<int> p3 = p1;
cout << p3.use_count() << endl;
*p1.get() = 10;
cout << "p1: " << *p1 << endl;
weak_ptr<int> p4(p1);
cout << p3.use_count() << endl;
return 0;
}