您的位置:首页 > 编程语言 > C语言/C++

new深入剖析 c++

2014-09-29 16:53 211 查看
结论1:new操作符会调用new函数和构造函数,我们只能重载new函数。new操作符不像其他操作符一样是一个显示的函数。以下1.1和1.2都是new操作符,即只要不是显示的函数调用,其他的都是new操作符

结论2:new操作符要么匹配成员new函数,要么匹配全局new函数,不能同时匹配成员和全局new函数

结论3:new操作符有两个过程,一是调用operator new()函数,二是调用构造函数在operator new()返回的地址上构造对象

----------------------------------------------------------------------------------------------------------------------------------------------

一、new 的语法有

1.1 A* ptr = new A(constructor-para-list);

1.2 A* ptr = new (para-list) A(constructor-para-list);

1.3 A* ptr = operator new(size);

二、new 的上述语法涉及到的函数

2.1 void* operator new(size_t size)

C++提供了一个全局的 void* operator new(size_t size)函数,该函数的作用就是用来申请空间,其底层实现就是使用了malloc,实现代码可在文章后面附录1看到。该函数可以被重载(重载为类的成员函数或全局函数都可以),但是重载函数的第一个参数必须是size_t 类型。

三、接下来,我们来看下一个包含new的语句到底做了什么

请看下面的代码

class X
{
public:
    X() { cout<<"constructor of X"<<endl; }
    ~X() { cout<<"destructor of X"<<endl;}

    void* operator new(size_t size,string str)
    {
        cout<<"operator new size "<<size<<" with string "<<str<<endl;
        return ::operator new(size);        
    }

    void operator delete(void* pointee)
    {
        cout<<"operator delete"<<endl;
        ::operator delete(pointee);
    }
private:
    int num;
    int numb;
};

int main()
{
    X *px = new("A new class") X;
    delete px;

    return 0;
}




可以看出,语句 X* px = new("A new class") X; 调用了重载的operator new函数,以及X的默认构造函数。

operator new()函数可以重载为成员函数,也可以重载为全局函数。

如果成员函数有重载operator new()函数(重载一次或多次),那么new操作符调用的一定是operator new()成员函数中的某一个,不能调用全局的operator new()函数。如果operator new()没有被重载为成员函数,那么new操作符调用的是全局operator new()中的某一个

成员函数中有operator new()重载函数:

class X
{
public:
    X() { cout<<"constructor of X"<<endl; }
    ~X() { cout<<"destructor of X"<<endl;}
    
    void* operator new(size_t size,string str)
	{
    	cout<<"operator new size "<<size<<" with string "<<str<<endl;
	    return ::operator new(size);        
	}
    void operator delete(void* pointee)
    {
        cout<<"operator delete"<<endl;
        ::operator delete(pointee);
    }
private:
    int num;
    int numb;
};    
int main()
{
	X* px = new X;
    return 0;
}



提示找不到被调用的匹配函数X::operator new(size_t),因为只能调用成员new函数,不能调用全局new函数。

成员函数中没有operator new()重载函数:

class X
{
public:
    X() { cout<<"constructor of X"<<endl; }
    ~X() { cout<<"destructor of X"<<endl;}
    
  	void operator delete(void* pointee)
    {
        cout<<"operator delete"<<endl;
        ::operator delete(pointee);
    }
private:
    int num;
    int numb;
};    
 void* operator new(size_t size,string str)
{
    cout<<"operator new size "<<size<<" with string "<<str<<endl;
	return ::operator new(size);        
}
int main()
{
	X* px = new X;
	delete px;
    return 0;
}



四、delete 扩展

delete操作符先调用析构函数,再调用operator delete()函数。

operator delete()只能被重载为两种形式

4.1 void operator delete(void* ptr)

4.2 void operator delete(void* ptr, size_t size)

delete的用法就一种:delete ptr;

delete ptr; 调用的delete函数首先是4.1,只有当4.1找不到的时候,才会调用4.2;4.2中size的值实质上是sizeof(*ptr)

和new一样,如果成员函数有delete函数,那么delete操作符只会匹配成员delete函数,不会匹配全局delete函数。如果成员函数没有delete函数,则delete操作符只会匹配全局delete函数。

五、new、delete对

malloc - free // A* pa = (A*)malloc(sizeof(A)); free(pa);

operator new - operator delete // A* pa = operator new(sizeof(A)); operator delete(pa);

new - delete // A* pa = new A; delete pa;

// A* pa = new (para-list) A; delete pa;

new[] - delete[] // A* pa = new A[10]; delete[] pa;

六、placement new

placement new的用法就是 A* pa = new (ptr) A(constructor-para-list);实质上就是重载了 operator new()函数。它的效果就是在ptr开始的位置上构造一个A类的对象。

网上说其实现代码如下:

inline _LIBCPP_INLINE_VISIBILITY void* operator new  (std::size_t, void* __p) _NOEXCEPT
 {return __p;}
上述的代码应该没问题:因为构造函数是在operator new()返回的地址上构造对象。

另外,placement new要包含头文件 <new>,因为重载的new函数是在该头文件中实现的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: