C++成员变量的new操作应该放在构造函数中吗?

来源:互联网 发布:linux 看网站访问ip 编辑:程序博客网 时间:2024/06/06 04:23

C++类中的指针成员变量(生命期紧随该类)的new操作,应该在类的构造函数中?还是需要一个Init()函数,也就是在构造函数外?为了解决这个问题,写个例子测试下。。


首先定义三个类,没有什么重要意义

class A{public:A(){ std::cout << "A()" <<std::endl; }~A(){ std::cout << "~A()" <<std::endl; }};class B{public:B(){ std::cout << "B()" <<std::endl; }~B(){ std::cout << "~B()" <<std::endl; }};class C{public:C(){ std::cout << "C()" <<std::endl; }~C(){ std::cout << "~C()" <<std::endl; }};

现在抛出问题,下面两段代码,那种的处理方式比较好呢?

代码1:

class Test{public:Test(){a_ = new A;b_ = new B;c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};
代码2:

class Test{public:Test(){}void Init(){a_ = new A;b_ = new B;c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};

对于上面的两个代码的调用如下:

//代码1执行如下:Test * test1 = new Test;delete test1;//代码2执行如下:Test * test2 = new Test;test2->Init();delete test2;

输出的结果都如下:

A()B()C()~A()~B()~C()

到目前为止,好像并不能发现两段代码有什么不同之处!  但是别着急。


看看异常出现的时候(throw模拟异常),会有怎样的结果:看看以下这两个代码

代码1:

class Test{public:Test(){a_ = new A;b_ = new B;throw std::string("构造函数中抛出异常");c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};int main(int argc, char *argv[]) {Test * test = NULL;try {test = new Test;} catch (const std::string& str) {std::cout << str << std::endl;}delete test;std::cout << "main end" << std::endl;return 0;}
输出结果:

A()B()构造函数中抛出异常main end


代码2:
class Test{public:Test(){}void Init(){a_ = new A;b_ = new B;throw std::string("Init()中抛出异常");c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};int main(int argc, char *argv[]) {Test * test = NULL;try {test = new Test;test->Init();} catch (const std::string& str) {std::cout << str << std::endl;}delete test;std::cout << "main end" << std::endl;return 0;}
输出结果:

A()B()Init()中抛出异常~A()~B()~C()new(4421,0x7fffd62833c0) malloc: *** error for object 0x7fffd6110010: pointer being freed was not allocated*** set a breakpoint in malloc_error_break to debug     //小编注,错误原因是c_没有初始化,是一个随机数,delete会产生崩溃

分析上面的例子,很明显可以发现:

代码1:调用了A、B的构造函数,但是没有调用A、B的析构函数,程序运行结束,造成了内存泄漏;

代码2:调用了A、B的构造函数,调用了A、B、C的析构函数。因为c_没有调用构造函数,却去析构它(此时c_是随机值),因此程序崩溃。


到了这里,你可能会觉得,那两种方式都有问题的,那该怎么写呢?? 但是,还是别着急,分析上面两个代码出错的原因,可以联想到delete NULL,是的,C++的delete兼容NULL,析构空并不会报错!!

所以上面的代码2可以修改成这样:

class Test{public:Test(){a_ = NULL;b_ = NULL;c_ = NULL;}void Init(){a_ = new A;b_ = new B;throw std::string("Init()中抛出异常");c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};int main(int argc, char *argv[]) {Test * test = NULL;try {test = new Test;test->Init();} catch (const std::string& str) {std::cout << str << std::endl;}delete test;std::cout << "main end" << std::endl;return 0;}
输出结果如下:

A()B()Init()中抛出异常~A()~B()main end


perfect!!!完美解决,没有内存泄漏,程序没有崩溃!!!

最后再试试上面的代码1,看能不能通过赋空解决呢?

class Test{public:Test(){a_ = NULL;b_ = NULL;c_ = NULL;a_ = new A;b_ = new B;throw std::string("构造函数中抛出异常");c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};int main(int argc, char *argv[]) {Test * test = NULL;try {test = new Test;} catch (const std::string& str) {std::cout << str << std::endl;}delete test;std::cout << "main end" << std::endl;return 0;}
运行一下,还是老样子(内存泄漏),朽木不可雕也,抛弃!


最后的最后,总结下,构造函数中尽量不要有new的操作,new的操作可以定义一个Init()来单独处理,代码如下:

class Test{public:Test(){a_ = NULL;b_ = NULL;c_ = NULL;}void Init(){a_ = new A;b_ = new B;c_ = new C;}~Test(){delete a_;delete b_;delete c_;}private:A* a_;B* b_;C* c_;};

阅读全文
0 0
原创粉丝点击