C++问题,关于构造函数中代码随机抽取函数。

提高C++代码质量&-&[041]谨防因构造函数抛出异常而引发的问题
概述:构造函数抛出异常常会引起对象的部分构造,因为不能自动调用析构函数,在异常发生之前分配的资源将得不到及时的清理,进而造成内存泄漏问题。
在C++中,对象构造过程中抛出的异常是一个比较棘手的问题,因为虽然抛出了异常,可是这个对象已经被赋予了部分生命,处于一个半死不活的状态。如下代码:
//不安全代码
class CObject
m_pSubObject = new CSubObject();
~CObject()
//...do other things
delete m_pSubO
&&& CSubObject*
安全版本1 发生异常时先清理已创建的资源,再抛出异常
//安全代码1
CObject::CObject()
m_pSubObject = new CSubObject();
delete m_pSubO
//抛出异常,交给上层处理
安全版本2 用智能指针
//安全代码2
class CObject
m_pSubObject = new CSubObject();
//...尽管去产生异常吧
~CObject()
//对象的清理工作交由智能指针去做
std::auto_ptr&CSubObject&
};//不要忘了建议34提到的auto_ptr的一些缺陷
“非常规”方法-在类中增加Init()和Release()函数
//安全代码3
class CObject
m_pSubObject = NULL;
if (!Init())
&&&&&&&&&&&
Release();
~CObject()
Release();
&&&&&&&&&&&
m_pSubObject = new CSubObject();
&&&&&&&&&&&
//...other data.s initiations
catch (...)
&&&&&&&&&&
&if (NULL == m_pSubObject)
&&&&&&&&&&
delete m_pSubO
m_pSubObject = NULL;
&&& CSubObject*
&&& //...other
member data
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。c++中构造函数调用另一构造函数的问题
关于C++构造函数调用的问题,在网上发现一一篇不错的文章,转载如下:
首先给出一道C++面试题目如下:
问下列代码的打印结果为0吗?
#include &stdlib.h&
#include &iostream&
struct CLS
CLS( int i ) : m_i(i){}
int main()
cout && obj.m_i &&
system(&PAUSE&);
我当时是这样想的,构造函数就是为对象分配内存的过程,其主要目的就是为了对私有变量进行初始化,所以我就想一个对象不能调用两次构造函数,即使这两种构造函数是重载过的,像题目中的
因为不太确定,回来查了一下,原来我之前的理解虽然沾了点边,但是还是没有想到点子上去。
首先在对象没有动态资源的时候,对象的内存分配在构造函数之前,此时构造函数的主要任务就是初始化对象的private成员,内存分配在构造函数执行之前,所以构造函数里调用另一种形式的构造函数(带参数的构造函数),其实编译器又生成了一个临时对象,这个临时对象的private成员通过其参数得到初始化,但是原来的对象的数据成员并没有初始化,是个随机值。
看了下面的测试代码,你就会明白一切
// 构造函数调用构造函数的问题.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &iostream&
class Widget
Widget(int n)
cout&&&有参数的构造函数中的this:&&&this&&
cout&&&无参数的构造函数中的this:&&&this&&
Widget(8888);
void print() const
cout&&&m_idata is:&&&m_idata&&
int _tmain(int argc, _TCHAR* argv[])
a.print();
system(&pause&);
很明显在两个构造函数中分别是两个对象,而且原对象的private成员是个随机值,所以我们要尽量避免在构造函数中调用另一形式的构造函数,那么构造函数调用自身就可以了吗?当然不行,这样会陷入无穷递归,有兴趣的可以实验一下
如果实在避免不了构造函数调用另一形势的构造函数时怎么办?网上查了下,可以用下面的方法解决:
new (this)CLS(8888)
这种方式是在原来的对象上调用另一形势的构造函数,不会生成新的临时对象。
下面是演示代码:
// 构造函数调用构造函数的问题.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
#include &iostream&
class Widget
Widget(int n)
cout&&&有参数的构造函数中的this:&&&this&&
cout&&&无参数的构造函数中的this:&&&this&&
new (this)Widget(8888);
void print() const
cout&&&m_idata is:&&&m_idata&&
int _tmain(int argc, _TCHAR* argv[])
a.print();
system(&pause&);
程序输出:
这时就没有哪个临时对象了,而且private数据成员已被初始化
总结:不带参数的构造函数的实现里去调用带参数的构造函数时,并没有完成对象内部的函数调用,而是优先选择了通过带参数构造函数又构造出了一个新的临时对象,所以尽量避免在构造函数中调用构造函数,不管是构造函数自身还是重载过的构造函数。
本文转自:http://blog.chinaunix.net/uid--id-3549733.html
欢迎与本站!
QQ交流群1:
QQ交流群2:本文主要回答C++和Java中,构造函数调用构造函数的问题。在这之前我们需要搞清楚一个问题,栈和堆。栈是拿来存在函数调用的临时数据的,堆是用来为程序分配类存的。但C++和Java还是有一些区别: Java:Java自动管理栈和堆,程序员不能直接地操作堆和栈。Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的指针(引用变量)而已。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 C++:在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new/new[]就要对应一个delete/delete[]。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。 Java的对象不存在于栈上,而C++却是可以的 构造函数之间应该共用代码。 构造函数的主要目的是初始化类的成员,获取必要的资源。一个好的类,应该在构造出来的时候,所有成员都是有合理值的。不存在尚未初始化的成员。为了满足不同的外部接口需求,我们可能会提供很多歌构造函数,一个通用的原则就是尽量复用构造函数代码。一个最直接的办法就是封装一个私有函数,然后构造函数都调用它: class&Constructer&{public:&&&&Constructer()&&&&{&&&&&&&&setA();&&&&};&&&&~Constructer()&&&&{&&&&&&&&std::cout&&&&&Destructor&&&&&std::&&&&};&&&&Constructer(int&i)&&&&{&&&&&&&&setA(i);&&&&&&&&std::cout&&&&&Constructer&with&para...&a&=&&&&&&a&&&&&std::&&&&};private:&&&&void&setA(int&v&=&0)&&&&{&&&&&&&&a&=&v;&&&&};private:&&&&int&a;};void&main(){&&&&Constructer();} 直接构造函数调用构造函数是不允许的。如果你先写了一个参数丰富,功能完备的构造函数,然后想提供一下缺省参数来提供新的构造函数,C++和Java都是不直接允许的。 在C++上,我们可以使用Replacement new实现。C++的new实际上分为两个阶段,第一阶段是分配内存,第二阶段是在分配还的内存上构造对象。Replacement new告诉编译器直接开始做第二阶段的工作,第一阶段的工作我给你提供。this指向的是类的对象的开始内存位置,在这个位置上构造对象的效果跟new是一样的,只是现在我们可以控制构造对象使用哪一个构造函数。 class&Constructer&{public:&&&&Constructer()&&&&{&&&&&&&&std::cout&&&&&Constructer&&&&&std::&&&&&&&&new&(this)Constructer(8);&&&&&&&&new&(this)Constructer(7);&&&&};&&&&~Constructer()&&&&{&&&&&&&&std::cout&&&&&Destructor&&&&&std::&&&&};&&&&Constructer(int&i)&:&a(i)&&&&{&&&&&&&&std::cout&&&&&Constructer&with&para...&a&=&&&&&&a&&&&&std::&&&&};private:&&&&int&a;};void&main(){&&&&Constructer();} C++的这种操作方式还有一个好处是可以在调用另外的构造函数之前做一些别的事情。这在Java中是不允许的。其实如果这些前置的操作没有操作类的成员,应该理论上市可行的。Java不允许只是执行了更加严格的要求而已。 Java里面可以通过this来实现构造函数调用构造函数。当然,类似于前面封装一个私有函数也是可以的。 public&class&Constructer&{&&&&public&Constructer()&&&&{&&&&&&&&//&NO&CODE&HERE&&&&&&&&this(&No&);&&&&&&&&System.out.println(&Constructer&);&&&&}&&&&public&Constructer(String&i)&&&&{&&&&&&&&System.out.println(&Constructer&with&para&=&&&+&i);&&&&}&&&&public&static&void&main(String[]&args)&&&&{&&&&&&&&new&Constructer();&&&&}} Java还有一个限制是this构造函数只能调用一次。C++却允许Replacement New任意次。这从理论上讲也是可行的,相当于重新初始化。Java不允许的原因,我猜测应该是语法解析的时候,看this构造函数前面有没有语句,有则直接报错。非常粗鲁的做法。相比而言,C++还是灵活很多。 虽然我们知道了怎么绕过去。但是还是得思考为什么不直接允许这样做呢?我的理解是,构造函数是特殊的成员函数,它只可以适用与第一次构造对象时。并且作为对象的函数,在对象还没有new出来的时候,对象并不存在,所以调用对象的方法也就没有任何意义。
标签常见用法
最新教程周点击榜
微信扫一扫}

我要回帖

更多关于 excel随机抽取函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信