Thinking in C++ 第13, 14, 15章(new和delete操作符的行为、虚函数的特殊情况)

一、动态对象创建

C++中,创建一个对象会发生两件事:

1. 为对象分配内存;

2. 调用构造函数来初始化那个内存。

 

newmalloc的区别

这也是一个较常见的面试题,malloc只是为对象申请了一定大小的内存;而new做了两件事,一是为对象分配内存,二是调用对象的构造函数。

deletefree的区别

free只是释放了对象所占用的内存;而delete做了两件事,一是调用对象的析构函数,二是释放对象的内存。

 

delete只用于删除由new创建的对象。如果用malloc创建一个对象,然后用delete删除它,这种行为是未定义的。:大多数默认的newdelete实现机制都使用了mallocfree

小心delete void*

如果你使用delete操作符删除一个void *类型的对象,那么这个对象的内存能够被正常释放,但是这个对象的析构函数却不会被调用,因为delete无法找到适当的类型信息。这有可能会造成资源泄露。

 

new-handler

当内存不够用时,std::set_new_handler函数允许我们指定一个函数,以处理这种情况。

详细的介绍,参考《Effective C++Item 49

二、将基类的析构函数设计为virtual

看如下情况:

假设有一个基类Base, 一个派生类Derive

Base *b = new Derive;

delete b;   // 调用谁的析构函数?

如果Base的析构函数是virtual的,那么delete将调用Derive的析构函数,这是正确的调用,b将会被正确的删除。但是如果Base的析构函数不是virtual的,那么delete将调用Base的析构函数,而将这意味着,Derive类中的某些资源没有被释放,这就造成了资源泄露。

更加详细的描述见《Effective C++Item7

三、构造函数中的虚机制被忽略

在普通的函数中调用一个虚函数,那么这个虚函数的行为是在运行时决定的;但是在构造函数中调用一个虚函数,被调用的只是这个函数的本地版本,也就是说虚机制在构造函数中不工作

首先,基类的构造函数在派生类的构造函数被调用之前进行,这意味着当基类的构造函数被调用时,派生类中的成员还没有被初始化。如果在构造函数中允许虚机制,那么在基类构造函数中调用一个虚函数可能会用到派生类中还没有初始化的成员,这就可能会引起错误。

另外,当一个构造函数被调用时,它做的首要的事情之一就是初始化它的VPTR。当编译器为这个构造函数产生代码时,它所使用的VPTR只能是它本身的VTABLE,因为此时它的派生类(如果有的话)的构造函数还没有被调用。因此从虚函数的机制层面上来说,构造函数中的虚函数也是不起作用的。

四、析构函数中的虚机制被忽略

同构造函数一样,在析构函数中,虚机制不起作用

这是因为,在对象进行析构时,总是先删除派生类,后删除基类,那么如果虚机制在析构函数中起作用,则在基类中调用的某个虚函数,而这个虚函数需要操作派生类中的成员,这时错误便发生了,因为此时派生类中的成员已经被删除了。

因此在析构函数中VPTR的信息存在,但是却并不可靠。

以后要看的

1. 内存管理

2. 数组名与一般指针的区别(常量性,…)

3. 重载newdelete(Effective C++)

4. C++虚函数动态绑定的实现原理(Think in C++, Inside C++ Object Model)

原文地址:https://www.cnblogs.com/hdtianfu/p/2296186.html