placement new和placement delete(重载new和delete2)

原创 2015年11月21日 11:30:20

placement new和placement delete

参考:《Effective C++》


(1) 什么是placement new和placement delete

placement new和placement delete已经被纳入了C++标准库中
下面是codeblock库中< new >对于二者的声明。

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p);
inline void* operator new[](std::size_t, void* __p);

// Default placement versions of operator delete.
inline void operator delete  (void*, void*);
inline void operator delete[](void*, void*);

placement版本的new和delete初衷是用于在vector中未使用的空间上创建对象的。

如果不特别说明,我们口中的placement 版本的new和delete指的就是上面的几种。

当然我们也可以自定义一些placement 版本(比如带有log功能的new):

void * operator new(size_t size,std::ostream & logger)
throw(std::bad_alloc);

(2) 如何使用placement版本的new和delete

#include <iostream>
#include <new>

#define BUFSIZ 512
char *BUF[BUFSIZ]{0};//申请一片内存

int main(){
    std::cout<<"BUF Addr:"<<BUF<<std::endl;
    int *p(new (BUF)int[10]);//BUF内分配一块内存给10个int类型的数据
    std::cout<<"P   Addr:"<<p<<std::endl;
    for(int i=0;i<10;i++){p[i]=i;}
    for(int i=0;i<10;i++){std::cout<<p[i]<<"  ";}
    std::cout<<'\n';
    return 0;
}

这里写图片描述
上面的例子就是在模拟vector的内存分配:在已有的但是未使用的BUF中分配内存。


(3) 从内存泄露出发

为什么我们需要placement版本的new和delete呢?
答:实际的需要。就像vector的内存处理方式。

我们不如从内存泄漏出发,细说placement版本的new和delete。


(a) 什么时候new一个对象会发生内存泄露?

#include <iostream>
#include <new>
#include <cstdlib>

class demo{
public:
    demo():m_dat(100){
        throw 1;
    }
    //palcement版本的new和delete
    void *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){
        return malloc(size);
    }
    //非placement版本的new和delte
    void operator delete(void *p)throw(){
        free(p);
    }
private:
    int m_dat;
};

int main(){
    demo *p(new (std::cerr)demo);
    return 0;
}

当new(std::cerr)demo被调用时,new操作成功并返回一块内存,但是demo的构造函数却抛出了异常。当然C++运行期系统考虑到了这种情况,当该情况发生时,系统会自动调用相应版本的delete正确地释放这块内存。

但是new的版本非常多,系统怎么知道调用那个版本呢?
答:系统会寻找参数个数和类型都与new相同的某个delete(这里指的是额外的参数相同,额外的参数指除了new需要size_t和delete需要void*之外的参数)

所以,我们容易知道,上述代码的内存泄露在:palcement版本的new没有对应的placement版本的delete可供调用,所以系统不做任何操作。

解决方法很简单,重载一个相应的operator delete即可:

class demo{
public:
    demo():m_dat(100){
        throw 1;
    }
    //palcement版本的new和delete
    void *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){
        return malloc(size);
    }
    //非placement版本的new和delte
    void operator delete(void *p)throw(){
        free(p);
    }
    //重载相应的placement版本的delete
    void operator delete(void *p,std::ostream&logger)throw(){
        std::cout<<"Placement operator delete"<<std::endl;
        free(p);
    }
private:
    int m_dat;
};

这样,系统就能够正确地选择new和delete。

所以铭记:重载了new就要重载相应版本的delete


(b) 当placement new和placement delete遇到继承

问题源:任何版本的new和delete重载都会覆盖默认的版本。
默认版本的new和delete有这些:

void *operator new(size_t)throw(std::bad_alloc);
void *operator new(size_t,void*)throw();
void *operator new(size_t,const std::nothrow_t&)throw();

当上述任一版本的new都会被类中的任一版本的new重载所覆盖


上例子:

#include <iostream>
#include <new>
#include <cstdlib>

class demo{
public:
    demo():m_dat(100){
        throw 1;
    }
    //重载自定义版本的new
    void *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){
        return malloc(size);
    }
    //重载相应的delete
    void operator delete(void *p,std::ostream&logger)throw(){
        std::cout<<"Placement operator delete"<<std::endl;
        free(p);
    }
private:
    int m_dat;
};

int main(){
    demo *p(new demo);
    return 0;
}

codeblock的错误:
这里写图片描述


VS2015的错误:
这里写图片描述


我在:重载new和delete的一些规则的特殊规则1中提及:一个类的operator new和operator delete 大都是为了本个类服务的,而不是它的派生类。

所以,当一个类重载了new和delete,它就会覆盖全局的,或是基类的new和delete。有时我们需要将这些版本的(比如基类中的)new和delete在本类中同样可以使用,我们该如何做呢?

*如果没有涉及到继承,而是局部和全局之间的覆盖的话,可以直接使用双冒号(::)来调用全局的new和delete,例如:::operator new(size)

让类支持global版本的new和delete(通过继承和using)

#include <iostream>
#include <new>
#include <cstdlib>

class StandardNewDelete{
public:
    static void *operator new(size_t size)throw(std::bad_alloc){return ::operator new(size);}
    static void *operator new(size_t size,void *ptr)throw(){return ::operator new(size,ptr);}
    static void *operator new(size_t size,const std::nothrow_t&nt)throw(){return ::operator new(size,nt);}
    static void operator delete(void *p)throw(){::operator delete(p);}
    static void operator delete(void *p,void *ptr)throw(){::operator delete(p,ptr);}
    static void operator delete(void *p,const std::nothrow_t& nt)throw(){::operator delete(p,nt);}
};

class demo:public StandardNewDelete{
public:
    demo():m_dat(100){}

    //使该类支持global版本的new和delete
    using StandardNewDelete::operator new;
    using StandardNewDelete::operator delete;

    void *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){
        return malloc(size);
    }
    void operator delete(void *p,std::ostream&logger)throw(){
        std::cout<<"Placement operator delete"<<std::endl;
        free(p);
    }
private:
    int m_dat;
};

int main(){
    demo *p(new demo);
    return 0;
}

**转载请注明出处

版权声明:本文为博主原创文章,未经博主允许不得转载。

关于C++的placement new和placement delete

昨天发贴提了个问题,今天总结在这。原帖点击进入,有兴趣可以看看,我呆会儿还会说。 C++的new是语言自定义的操作符,这个操作符的行为包含两件事,而且你不能改变。 第一件事:调用operato...
  • High_High
  • High_High
  • 2012年03月27日 01:03
  • 6729

c++ placement new操作符的使用技巧

在c++中new和delete操作是我们操作内存最常用的一对操作符,在使用new时编译器会申请内存,然后调用类的构造函数来初始化对象,调用delete会销毁对象同时释放该对象占用的内存,并且我们可以重...
  • D_Guco
  • D_Guco
  • 2017年01月04日 23:18
  • 1338

《Effective C++》:条款52:写了placement new也要写placement delete

placement new和placement delete是C++经常用到但是却不常见的两个操作符。但是两者要有对应关系...
  • KangRoger
  • KangRoger
  • 2015年03月26日 12:20
  • 1363

条款52:写了placement new也要写placement delete

条款52:写了placement new也要写placement delete    Write placement delete if you write placement new.    我们都...
  • scofieldzhu
  • scofieldzhu
  • 2009年10月28日 11:12
  • 1894

c++placement new

初次接触到placement new,在在看安卓的audio模块代码,
  • u010657219
  • u010657219
  • 2014年10月18日 11:01
  • 883

placement new和placement delete

在第五版的《C++ primer》中,定位new
  • lc_910927
  • lc_910927
  • 2014年06月10日 14:42
  • 830

C++ placement new与内存池

C++ placement new结合内存池完美避开各种内存问题~
  • Kiritow
  • Kiritow
  • 2016年05月04日 14:42
  • 510

全面解析C++中的new,operator new与placement new

全面解析C++中的new,operator new与placement new   以下是C++中的new,operator new与placement new进行了详细的说明介绍,需要的朋友...
  • walkerkalr
  • walkerkalr
  • 2014年03月27日 12:54
  • 666

C++中的定位放置new(placement new)

一般来说,使用new申请空间时,是从系统的“堆”(heap)中分配空间。申请所得的空间的位置时根据当时的内存的实际使用情况决定的。但是,在某些特殊情况下,可能需要在程序员指定的特定内存创建对象,这就是...
  • K346K346
  • K346K346
  • 2015年10月30日 17:03
  • 2412

重载new和delete的一些规则

重载new和delete的一些规则重载new和delete的一些规则 一般规则 特殊规则1 特殊规则2 特殊规则3 new和delete重载实例 直接获取当前的new_handler 转载请注明出处参...
  • sanoseiichirou
  • sanoseiichirou
  • 2015年11月20日 23:18
  • 1312
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:placement new和placement delete(重载new和delete2)
举报原因:
原因补充:

(最多只允许输入30个字)