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. 作为一枚第二天上班的小小.net程序员(技术宅的那种)很迷茫哦,第一个随笔

    作为一枚第二天上班的小小.net程序员(技术宅的那种)很迷茫哦,第一个随笔

  2. oracle装载表是什么?

    oracle装载表即通过sqlloader的方式导入数据. Oracle 的SQL*LOADER可以将外部数据加载到数据库表中.下面是SQL*LOADER的基本特点: 1)能装入不同数据类型文件及多个 ...

  3. 使用w查看系统负载 vmstat命令 top命令 sar命令 nload命令

    w/uptime 查看系统负载 w查看系统负载,uptime跟w一样. [root@centos7 ~]# w 22:34:10 up 6 days, 23:10,  4 users,  load a ...

  4. drools研究后记

    在实际工作中,有关于达标推断的业务逻辑 就是谁谁谁 消费满了多少钱.就返多少钱的优惠券 声明:不是drools不好,仅仅是在我遇到的场景下,不合适,不够好 在使用drools的时候发现有例如以下问题: ...

  5. geoserver REST使用

    1.部署一个简单的测试环境 测试geoserver REST接口,我们可使用python来测试,很方便.需要下载包: python,http://python.org/.我下载的是Python27版本 ...

  6. yum 安装mysql, yum安装指定版本的mysql

    yum安装mysql: 1. 查看有没有安装过     yum list installed MySQL* (有存在要卸载yum remove MySQL*)     rpm -qa | grep m ...

  7. 使用psutil库监控linux的系统资源和自定义进程的cpu 内存占用。

    #coding=utf8 import time import psutil from pprint import pprint from logger_until import LoggerUnti ...

  8. linux 使用supervisor来管理进程

    现在假设一个脚本是,hello.py,内容是 fo = open('xx.txt','w') while 1: fo.write('hello world') print('hi') time.sle ...

  9. 实战c++中的string系列--不要使用memset初始化string(一定别这么干)

    參考链接: http://www.cppblog.com/qinqing1984/archive/2009/08/07/92479.html 百度百科第一次这么给力: void *memset(voi ...

  10. bat批处理设置静态、动态、ping、查看网络配置

    @echo off :startIP set /p source=S or D or C or P or E: echo source:%source% if /i "%source%&qu ...