C++随记

在析构函数中抛出异常,如果这时候已经有一个异常的话,程序会崩溃。

参考:http://www.cnblogs.com/KevinSong/p/3323372.html  ,以及《Effective C++》第8条。


  1. 构造函数中抛出异常,不会自动调用析构函数。但是已经分配的内存会自动释放,另外已经自动构造的成员变量会调用析构函数。
  2. 例如,在new Bar()中,Bar的构造函数抛出一个异常,不会自动调用~Bar(),成员变量的析构也不会调用
  3. 如果是成员变量的构造抛出异常,情况类似,不会调用成员的析构,即使是已经构造过的变量new结果返回NULL,因为对应的内存已经被释放。
  4. 结果是很有可能造成内存的泄露和资源未释放
  5. 抛出异常时,在退出当前堆栈之前,会自动析构当前作用域的本地变量。这也是C++异常处理不需要finally的原因。如果是动态构造出来的还需要手动处理,或者使用类似smart pointer机制。

参考《深度探索C++对象模型》7.2节。

就上面两条短评一下C++的异常处理机制。相对与Java当中的广泛应用,C++中的异常处理似乎受到人们的冷遇。我想有以下几个原因

  1. C++很多情况下被当做面向对象的C使用,一般局限在封装、继承和多态,高级功能使用得不多。Java没有类似的包袱,异常在各个类库里都是重要的组成部分。
  2. Java的finally机制更容易理解。stack unwinding的想法固然好,但是使用起来却容易顾此失彼。
  3. 缺乏checked exception机制。一个函数如果可能会抛出异常,那就需要在编译期解决这个问题。调用一个第三方类库,却不知道什么时候会抛出异常,用的人也是步步惊心。

在父类构造函数中调用虚函数,由于子类还没构造完成,虚函数表未建立,调用的还是父类的实现。如果调用的是纯虚函数,则程序会直接退出。事实上gcc会给出编译警告。

把子类变量赋值给一个父类变量,即使传值拷贝,也不会拷贝虚函数本身。即父类变量(不是引用不是指针)无论如何不会调用子类的虚函数。

此条目发表在 技术 分类目录。将固定链接加入收藏夹。