码迷,mamicode.com
首页 > 其他好文 > 详细

智能指针的那些事

时间:2015-04-17 11:32:23      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:c++   智能指针   

C++不像Java,C#语言,它没有垃圾回收机制,但是它提供了强大而灵活的管理机制,使得开发人员自己避免内存泄露。可以通过new 获得内存或创建对象,一定使用delete来释放,这样就避免内存泄露。同时也可以将分配和使用用类封装,从而保证没有内存泄露。

#include <iostream>

using namespace std;

 

#include <stdio.h>

#include <string.h>

 

class simpleClass

{

private:

char *m_buf;

size_t m_size;

public:

simpleClass(size_t n = 1)

{

m_buf = new char[n];

m_size = n;

}

~simpleClass()

{

printf("%d is deleted at %xd \n", m_size, m_buf);

delete[] m_buf;

}

char * GetBuf()

{

return m_buf;

}

};

 

void foo()

{

simpleClass  a(10);

char *= a.GetBuf();

 

strcpy(p, "Hello");

printf("%s\n", p);

}

 

int main()

{

foo();

printf("exit main()...\n");

return 0;

}

这个程序中,对char类型的内存分配封装在类simpleClass中,通过声明对象,并给所需内存的大小,调用GetBuf获取响应内存,这段内存在simpleClass的对象退出时会调用析构函数自动释放。但是还是存在不完美的地方,如果在foo()函数中增加一条赋值语句

void foo()

{

simpleClass  a(10);

simpleClass b = a;

char *= a.GetBuf(); // 增加的语句

 

strcpy(p, "Hello");

printf("%s\n", p);

}

 技术分享

 

在实现simpleClass时,并没有实现拷贝构造函数,因此编译器会构造一个默认的拷贝构造函数,执行位拷贝(bit copy)操作,即对象a的内容一个个字节的拷贝到对象b中,因此对象a中的m_buf和拷贝后对象b中的m_buf指向的是同一个地址的内存。当ab都销毁时,m_buf中的内容被销毁两次。解决方案:

(1)禁止拷贝构造,将拷贝构造函数声明为私有的。

(2)使用引用计数,对使用内存维护一个计数器。当有指针指向这块内存,计数器加1,当指向这块内存的指针销毁时,计数器减1,只有当计数器减为0时,表示没有指针指向这块内存,这块内存才可以被释放。

#include <iostream>

using namespace std;

 

#include <stdio.h>

#include <string.h>

 

class simpleClass

{

private:

char *m_buf;

size_t m_size;

int *m_count;

public:

simpleClass(size_t n = 1)

{

m_buf = new char[n];

m_size = n;

 

m_count = new int; // 为m_count分配空间 

*m_count = 1;

printf("m_count is:%d\n", *m_count);

}

simpleClass(const simpleClass& s)

{

m_size = s.m_size;

m_buf = s.m_buf;

m_count = s.m_count;

(*m_count)++;

printf("m_count is:%d\n", *m_count);

}

~simpleClass()

{

(*m_count)--;

printf("m_count is:%d\n", *m_count);

if (== *m_count)

{

printf("%d is deleted at %d\n", m_size, m_buf);

delete[] m_buf;

delete m_count;

}

}

char * GetBuf()

{

return m_buf;

}

};

 

void foo()

{

simpleClass a(10);

char *= a.GetBuf();

 

strcpy(p, "Hello");

printf("%s\n", p);

 

simpleClass b = a;

printf("b=%s \n", b.GetBuf());

}

 

int main()

{

foo();

printf("exit main()...\n");

return 0;

}

 技术分享

分析:当a被构造时,m_count初始化为1,当执行b=a时,count增加为2和 b指向同一块内存,存储的内容都是“hello”。当退出foo()时,b首先被销毁,m_count1,但是m_count的值仍是大于0的,所以内存没有释放。当a销毁时,m_count的值减为0,才释放对应的内存。

如何在foo()函数里面添加两句代码

void foo()

{

simpleClass a(10);

char *= a.GetBuf();

 

strcpy(p, "Hello");

printf("%s\n", p);

simpleClass b = a;

 

// 添加代码

simpleClass c(20);

= a;

printf("b= %s,c= %s\n", b.GetBuf(), c.GetBuf());

}

 技术分享

 

在通过拷贝构造创建b之后,声明了一个c对象,申请的内存大小是20字节。然后a赋值给c,此时c指向了a的内存。而c原来指向的内存则无指针指向,因此被释放。但是程序没有处理,造成内存泄露。解决方案,使用运算符重载。

simpleClass& operator=(const simpleClass& s)

{

// 判断当前对象的 m_buf 是否和 s.m_buf 是否指向相同的地址 

if (m_buf == s.m_buf)

return *this;

 

// 如果不是,当前对象引用计数减1 

(*m_count)--;

 

// 如果引用计数为0,释放该对象指向的空间 

if (*m_count == 0)

{

printf("%d is deleted at %xd\n", m_size, m_buf);

delete[] m_buf;

delete m_count;

}

// 当前对象指针 指向新的地址空间 

m_buf = s.m_buf;

m_size = s.m_size;

m_count = s.m_count;

(*m_count)++;// 这也是为什么引用计数用指针的原因??

}

 技术分享

总算是没有错误了,但是这个智能指针还不完整,并没有实现真正指针那样的操作,如运算符*->都没有重载。更多详细内容参考《C++ Primer》 400页。

推荐书籍:

C++ Primer(5)

*****************************分割线************************************

如果喜欢,帮忙点赞,推荐给好友

添加方式,在微信公众号

搜索c语言每日一问

或者Love_gcc123

或者长按二维码图片,就可以添加

技术分享

智能指针的那些事

标签:c++   智能指针   

原文地址:http://blog.csdn.net/u014304293/article/details/45092367

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!