在c里,我们通过什么样的方法,可以避

对C++程序员来说,编写C++程序有一条必须注意的规则,就是在类中包含了一个指针成员的话,那么就要特别小心拷贝构造函数的编写,因为一不小心,就会出现内存泄露。下面我们就来了解一下吧。

我们来看看下面的代码清单中的例子。

#include<iostream>

usingnamespacestd;

classHasPtrMem{

public:

HasPtrMem():d(newint(0)){}

HasPtrMem(constHasPtrMem&h):

d(newint(*h.d)){}//拷贝构造函数,从堆中分配内存,并用*h.d初始化

~HasPtrMem(){deleted;}

int*d;

};

intmain(){

HasPtrMema;

HasPtrMemb(a);

cout<<*a.d<<endl;//0

cout<<*b.d<<endl;//0

}//正常析构

//编译选项:g++3-3-1.cpp

在上面的代码清单中,我们定义了一个HasPtrMem的类。这个类包含一个指针成员,该成员在构造时接受一个new操作分配堆内存返回的指针,而在析构的时候则会被delete操作用于释放之前分配的堆内存。

在main函数中,我们声明了HasPtrMem类型的变量a,又使用a初始化了变量b。按照C++的语法,这会调用HasPtrMem的拷贝构造函数。

这里的拷贝构造函数由编译器隐式生成,其作用是执行类似于memcpy的按位拷贝。这样的构造方式有一个问题,就是a.d和b.d都指向了同一块堆内存。

因此在main作用域结束的时候,a和b的析构函数纷纷被调用,当其中之一完成析构之后(比如b),那么a.d就成了一个“悬挂指针”,因为其不再指向有效的内存了。那么在该悬挂指针上释放内存就会造成严重的错误。

这个问题在C++编程中非常经典。这样的拷贝构造方式,在C++中也常被称为“浅拷贝”。

而在未声明构造函数的情况下,C++也会为类生成一个浅拷贝的构造函数。通常最佳的解决方案是用户自定义拷贝构造函数来实现“深拷贝”。

我们来看看下面的代码清单中的修正方法。

#include<iostream>

usingnamespacestd;

classHasPtrMem{

public:

HasPtrMem():d(newint(0)){}

HasPtrMem(HasPtrMem&h):

d(newint(*h.d)){}//拷贝构造函数,从堆中分配内存,并用*h.d初始化

~HasPtrMem(){deleted;}

int*d;

};

intmain(){

HasPtrMema;

HasPtrMemb(a);

cout<<*a.d<<endl;//0

cout<<*b.d<<endl;//0

}//正常析构

//编译选项:g++3-3-2.cpp

在上面的代码清单中,我们为HasPtrMem添加了一个拷贝构造函数。拷贝构造函数从堆中分配新内存,将该分配来的内存的指针交还给d,又使用*(h.d)对*d进行了初始化。通过这样的方法,就避免了悬挂指针的困扰。看完了文章,你学会了吗?




转载请注明:http://www.aierlanlan.com/grrz/4613.html

  • 上一篇文章:
  •   
  • 下一篇文章: