1. c++在调用构造函数时,才会把最开始的虚表指针指向虚表。

2.在构造函数或者析构函数中调用虚函数。

    编译上没有问题。

    运行时,调用虚函数不会发生多态行为,会调用正在构造的类的虚函数。

  详细可见c++中的说明:

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.).
When a virtual function is called directly or indirectly from a constructor (including the mem-initializer or
brace-or-equal-initializer for a non-static data member) or from a destructor, and the object to which the
call applies is the object under construction or destruction, the function called is the one defined in the
constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived
from the constructor or destructor’s class, or overriding it in one of the other base classes of the most derived
object (1.8). If the virtual function call uses an explicit class member access (5.2.) and the object-expression
refers to the object under construction or destruction but its type is neither the constructor or destructor’s
own class or one of its bases, the result of the call is undefined.

//大意就是上面提到的运行时,因为子类没有构造好(指向虚表的指针都还没有初始化),所以没有多态行为。但如果要显示在父类中调用子类的虚函数。那么会出现undefined行为。

3.new、operator new与placement new

new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。

new operator
1)  调用operator new分配内存 ;
2)  调用构造函数生成类对象;
3)  返回相应指针。

operator new
(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
        ->如果有new_handler,则调用new_handler,否则
        ->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
        ->返回0
(2)可以被重载
(3)重载时,返回类型必须声明为void*
(4)重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)重载时,可以带其它参数

//我的理解:new操作符(new operator)做的事情是不变的,首先会调用operator new,如果你的类重载了operator new,则会调用你重载的。没有重载的话,则调用::operator new

#include <iostream>
#include <stdlib.h>
using namespace std; class A { public:
A() {
cout << "A construct" << endl;
c = ;//程序会崩,因为this为NULL
} void * operator new(unsigned int sz) {
cout << "operator new" << endl;
return NULL;
}
int c; }; int main()
{
A *a = new A;
return ;
}

//从上面的代码可以看出,new A时,先调用了operator new, 然后再调用构造函数,因为operator new 返回的是NULL,所以执行到c = 1时,程序直接崩了。正好了证明了new操作符做的事情。

同理delete,new [], delete[]都可以重载相应的运算符。

placement new

placement new 是重载operator new 的一个标准、全局的版本,它不能够被自定义的版本代替(不像普通版本的operator new和operator delete能够被替换)。也就是无需、也不能重载。

void *operator new( size_t, void * p ) throw() { return p; }

//注意 throw()
它是函数提供者和使用者的一种君子协定,标明该函数不抛出任何异常。 之所以说是君子协定,是因为实际上内部实现是需要人肉确保。  如果一个标明throw()的函数内部发生了throw: 
,如果内部直接throw something,编译器会发现并指出; 
. 如果是内部调用了一个可能throw something的函数,编译器无法发现,运行时一旦这个内部的函数throw,程序会abort。 
这是异常规范,只会出现在声明函数中,表示这个函数可能抛出任何类型的异常,例如: 
void GetTag() throw(int);表示只抛出int类型异常 
void GetTag() throw(int,char);表示抛出in,char类型异常 void GetTag() throw();表示不会抛出任何类型异常 void GetTag() throw(...);表示抛出任何类型异常 void GetTag() throw(int);表示只抛出int类型异常 
并不表示一定会抛出异常,但是一旦抛出异常只会抛出int类型,如果抛出非 int类型异常,调用unexsetpion()函数,退出程序。 
假如你加一个throw()属性到你的永远不会抛出异常的函数中,编译器会非常聪明的知道代码的意图和决定优化方式

placement new的执行忽略了size_t参数,只返还第二个参数。其结果是允许用户把一个对象放到一个特定的地方,达到调用构造函数的效果。和其他普通的new不同的是,它在括号里多了另外一个参数。比如:

Widget * p = new Widget;                    //ordinary new

pi = new (ptr) int;    //placement new

括号里的参数ptr是一个指针,它指向一个内存缓冲器,placement new将在这个缓冲器上分配一个对象。Placement new的返回值是这个被构造对象的地址(比如括号中的传递参数)。

stl中用到了这个技巧。

比如:uninitalized_copy() 函数,就是依次拷贝数据时,调用拷贝构造函数,而不会调用赋值函数。

拷贝很多数据的时候,如果要调用赋值函数,那么就得new一个出来。然后再赋值,这无疑增加无用的开销。

最好的方法当然是,先申请整块内存空间,然后把数据拷贝过来。这个时候就需要用到placement new了。

在申请好的内存空间上调用拷贝构造函数。

stl源码剖析51页:

template <class T1, class T2>
inline void construct(T1*p, const T2& value) {
new (p) T1(value);//p调用T1的拷贝构造函数
}

4、拷贝(复制)构造函数为什么不能用值传

会产生死循环,因为如果值传递的话,调用拷贝构造函数的时候,传参时又会调用拷贝构造函数。导致死循环。

5、构造函数/析构函数抛出异常的问题

构造函数抛出异常:
    1.不建议在构造函数中抛出异常;
    2.构造函数抛出异常时,析构函数将不会被执行;
C++仅仅能删除被完全构造的对象(fully contructed objects),只有一个对象的构造函数完全运行完毕,这个对象才能被完全地构造。对象中的每个数据成员应该清理自己,如果构造函数抛出异常,对象的析构函数将不会运行。如果你的对象需要撤销一些已经做了的动作(如分配了内存,打开了一个文件,或者锁定了某个信号量),这些需要被撤销的动作必须被对象内部的一个数据成员记住处理。

析构函数抛出异常:
    在有两种情况下会调用析构函数。第一种是在正常情况下删除一个对象,例如对象超出了作用域或被显式地delete。第二种是异常传递的堆栈辗转开解(stack-unwinding)过程中,由异常处理系统删除一个对象。
在上述两种情况下,调用析构函数时异常可能处于激活状态也可能没有处于激活状态。遗憾的是没有办法在析构函数内部区分出这两种情况。因此在写析构函数时你必须保守地假设有异常被激活,因为如果在一个异常被激活的同时,析构函数也抛出异常,并导致程序控制权转移到析构函数外,C++将调用terminate函数。这个函数的作用正如其名字所表示的:它终止你程序的运行,而且是立即终止,甚至连局部对象都没有被释放。
概括如下:
    1.析构函数不应该抛出异常;
    2.当析构函数中会有一些可能发生异常时,那么就必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外;
    3.当处理另一个异常过程中,不要从析构函数抛出异常;

在构造函数和析构函数中防止资源泄漏的好方法就是使用smart point(智能指针),C++ STL提供了类模板auto_ptr,用auto_ptr对象代替原始指针,你将不再为堆对象不能被删除而担心,即使在抛出异常时,对象也能被及时删除。因为auto_ptr的析构函数使用的是单对象形式的delete,而不是delete [],所以auto_ptr不能用于指向对象数组的指针。当复制 auto_ptr 对象或者将它的值赋给其他 auto_ptr 对象的时候,将基础对象的所有权从原来的 auto_ptr 对象转给副本,原来的 auto_ptr 对象重置为未绑定状态。因此,不能将 auto_ptrs 存储在标准库容器类型中。如果要将智能指针作为STL容器的元素,可以使用Boost库里的shared_ptr。

C++构造函数、new、delete的更多相关文章

  1. C++构造函数、析构函数与抛出异常

    [本文链接] http://www.cnblogs.com/hellogiser/p/constructor-destructor-exceptions.html [问题] 构造函数可以抛出异常么?析 ...

  2. 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。

    (1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...

  3. C++中的new/delete与operator new/operator delete

    new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数. new operator(1)调用opera ...

  4. C++ new和delete实现原理——new和delete最终调用malloc和free

    new和delete最终调用malloc和free,关于malloc和free实现原理参见这篇文章: http://blog.csdn.net/passion_wu128/article/detail ...

  5. 详解new/delete(整合)

    C++中内存的动态分配与管理永远是一个让C++开发者头痛的问题,本文通过对C++中内存的动态分配释放的基本原理的介绍,让读者朋友能对C++中的内存的动态分配与释放有较为深入的理解,从而更好驾驭C++程 ...

  6. C++ delete 和 delete []

    C++ delete 和 delete [] 简单结论: new delete new [] delete []   文章 : 对 delete [] 的声明 void operator delete ...

  7. 深度剖析malloc、free和new、delete

    1.malloc,free是C语言的函数,而new,delete是操作符,属于C++的语法,一定注意这两个不再是函数了,而是操作符. 2.malloc和new对于分配基础类型变量和数组变量,它们除了语 ...

  8. 一起学HBase——总结HBase中的PUT、GET、DELETE操作

    传统的关系型数据库有CRUD增删改查操作,同样对于NoSQL列式数据库也有CRUD操作.本文对HBase中常用的Scan.GET.PUT.DELETE操作的用法做个总结. Put操作 Put相当于传统 ...

  9. C++ new/malloc、delete/free

    1.new和delete是运算符,可以被重载:malloc和free是库函数,不能被重载. 2.new会调用对象的构造函数,delete会调用对象的析构函数:malloc和free不会.

  10. C++构造函数和析构函数,以及构造函数特殊成员变量和函数的初始化

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

随机推荐

  1. C#-----------------------------回收机制中Destroy与null的作用

    关于Object被Destroy之后,该Object的原引用==null的问题 标签: unityc#继承对象 2017-01-23 23:32 506人阅读 评论(0) 收藏 举报  分类: Uni ...

  2. C#提高-------------------Assembly和Module的使用-------反射内涵

    转 :C#反射技术概念作用和要点 反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以 ...

  3. 精美的HTML5/CSS3表单 带小图标

    今天我们要来分享一款非常精美的HTML5/CSS3表单,准备地说,这是一款经过美化的input输入表单,每一个输入表单都可以定义其两侧的小图标,非常华丽.另外,这款表单应用还采用了3种不同的风格主题, ...

  4. 一款CSS3仿Google Play的垂直菜单

    之前分享过一款非常酷的CSS3垂直下拉动画菜单,是多级菜单.今天我们来看一款也是用CSS3制作的垂直菜单,是仿Google Play的菜单,菜单项都带有可爱的小图标,可以先来看看效果图: 当然你可以在 ...

  5. asp.net存储过程分页+GridView控件 几百万数据 超快

    存储过程:---亲测275万数据,分页速度N快 ))+' '+@orderid+' from '+@tablename+' '+@tmpOrderid set @sql='select top'+st ...

  6. 关于Struts2的多文件上传

    之前写过一篇文章,关于Struts2文件上传:http://www.cnblogs.com/lichenwei/p/3927964.html 现在来说下多文件上传,其实就把上传文件当成是一个数组去处理 ...

  7. POI简易帮助文档系列--读取Excel文件

    上篇博客通过简单的几行代码就学会了POI新建Excel文档的使用,本篇博客也从简单出发,通过查看POI的官网文档和一个简单的代码实例,学习怎么遍历出一个Excel文档的内容. package com. ...

  8. Oracle:在 debian9 上完美安装 oracle 10.2.0.5 x64

    多余废话不说. 多动脑子,思路不要僵化. 关键点: --------------------------------------------------- 安装i386的支持库:libc6-dev:3 ...

  9. Linux安装bundle

    安装bundle文件的方法: cd 到文件目录再用sudo chmod +x XXXXXXX.bundle 加权限最后 ./XXXXXXXX.bundle 就行了. 第一步:sudo chmod +x ...

  10. JointJS绘制流程图

    摘要: JointJS是一个javascript图表库.你可以使用它制作静态或者动态的图表.关系表.流程图. 效果图: