当前位置:   article > 正文

C++ new的三种用法_c++new的用法

c++new的用法

C++ new的三种用法

参考文章:

https://www.jb51.net/article/41524.htm

https://blog.csdn.net/aoeaoao/article/details/124553631

概述

  三种用法包括:plain new、nothrow new、placement new。

plain new

  顾名思义就是最普通的new的使用,在C++中定义如下:

void* operator new(std::size_t) throw(std::bad_alloc);

void operator delete(void *) throw();
  • 1
  • 2
  • 3

TIPS:plain new在分配失败下会抛出异常(std::bad_alloc),而不是返回NULL,即通过判断返回值是否为NULL,来断定是否分配失败是无效的。

实例

#include "stdafx.h"
#include <iostream>
using namespace std;
char *GetMemory(unsigned long size)
{
	char *p=new char[size];//分配失败,不是返回NULL
	return p;
}

int main()
{
	try
	{
		char *p = GetMemory(10e11);// 分配失败抛出异常std::bad_alloc
  		if(!p)					 //无效
   			cout<<"failure"<<endl;
  		delete [] p;
	}
	catch(const std::bad_alloc &ex)//正确写法
	{
  	cout<<ex.what()<<endl;
	}

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

nothrow new

  在内存分配失败的情况下,该方式不会抛出异常,而是返回NULL。在C++中定义如下:

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

void operator delete(void*) throw();
  • 1
  • 2
  • 3

实例

#include "stdafx.h"
#include <iostream>
#include <new>
using namespace std;

char *GetMemory(unsigned long size)
{
	char *p = new(std::nothrow) char[size];//分配失败,返回NULL
	if(NULL == p)
  		cout << "alloc failure!" << endl;
	return p;
}

int main()
{
	char *p=GetMemory(10e11);
  	if(NULL == p)
   		cout << "failure" << endl;
  	delete [] p;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

palacement new

  palacement意味”放置“,该方式是在一块已经分配的内存之上重新构造对象或对象数组。palacement new不用担心内存是否分配失败,因为其根本不分配内存,而是对已分配的内存再利用。它唯一做的事情就是在已有的空间上初始化对象,调用对象的构造函数。在C++中定义如下:

void* operator new(size_t, void*);

void operator delete(void*, void*);
  • 1
  • 2
  • 3

TIPS:palacement new需要显式调用对象的析构函数,不能使用delete/delete [],因为placement new构造起来的对象或数组大小并不一定等于原来分配的内存大小,使用delete/delete []会造成内存泄漏或者释放内存之后出现运行时错误。

实例

#include "stdafx.h"
#include <iostream>
#include <new>

using namespace std;

class ADT {
	int i;
	int j;
	public:
	ADT() {
	}
	~ADT() {
	}
};

int main() {
	char *p = new(nothrow) char[sizeof(ADT)+2];
	if(p == NULL)
  		cout << "failure" << endl;
	ADT *q = new(p) ADT;  //placement new:不必担心内存分配失败
    //delete q;			 //错误!不能在此处调用delete q;
	q->ADT::~ADT();		 //显式调用析构函数
	delete [] p;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

其他

TIPS:

格式:new(类对象指针) 类构造函数([参数])

上述格式可以显示调用类的构造函数。

实例

#include <iostream>

class Test2 {
public:
    Test2(int a_, int b_) {
        a = a_;
        b = b_;
        std::cout << "调用构造函数" << std::endl;
    }

    ~Test2() {
        std::cout << "调用析构函数" << std::endl;
    }

    void Print() {
        std::cout << a << " " << b << std::endl;
    }

    int a;
    int b;
};

int main()
{
    Test2* t2 = new Test2(1, 2);
    t2->Print();
    new(t2) Test2(2, 2);
    t2->Print();
    new(t2) Test2(4, 2);
    t2->Print();
	system("pause");
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

注意点

  在C++中”有内存空间不一样在内存空间中就有实例对象,而有实例对象,也不一定有内存空间“。

注释:第二部分比如函数的形参(局部变量),在函数调用的时候有实例对象和分配该实例对象的内存空间,但是当函数调用完毕时,形参的内存空间将被回收。

  我们知道,在C++中使用malloc申请内存,尤其是对类对象申请内存时,是不会主动调用类的构造函数的,即我们在该情况下应当显式调用类的构造函数。

  以下进行测试,我们同样知道,针对包含虚函数的类,在实例化类对象的时候,会生成相应的虚表以及虚表指针,以下进行测试,当我们不显式调用类的构造函数会出现什么情况。

#include <iostream>

class Test2 {
public:
    Test2(int a_, int b_) {
        a = a_;
        b = b_;
        std::cout << "调用构造函数" << std::endl;
    }

    ~Test2() {
        std::cout << "调用析构函数" << std::endl;
    }

    virtual void Print() {
        std::cout << a << " " << b << std::endl;
    }

    int a;
    int b;
};

int main()
{
    Test2* t2 = (Test2*)malloc(sizeof(Test2));
    /*new(t2) Test2(2, 2);*/
    t2->Print();

    //delete t2;
    t2->~Test2();
    free(t2);
	system("pause");
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

效果图

  而当我们显式调用类的构造函数时,情况如下:

int main()
{
    Test2* t2 = (Test2*)malloc(sizeof(Test2));
    new(t2) Test2(2, 2);
    t2->Print();

    delete t2;
    /*t2->~Test2();
    free(t2);*/
    
	system("pause");
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

效果图

应用

  在我们使用C++进行开发项目的过程中,我们可以定义一个全局申请内存的模块,用于管理在项目中所有申请内存的操作,如下:

Common.h

#pragma once

#include <iostream>
#include <map>

#define FIRST_CHOICE_MALLOC(len) FirstChoiceMalloc(len, __FILE__, __LINE__);


void* FirstChoiceMalloc(uint32_t len, const char* file, int32_t line);
void  FirstChoiceFree(void* p);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Common.cpp

#include "Common.h"

struct MallocBlockInfo {
    uint32_t    len;
    std::string file;
    int         line;
};

uint32_t g_blockSize = 0;
std::map<void*, MallocBlockInfo> g_blockMap;


void *FirstChoiceMalloc(uint32_t len, const char * file, int32_t line) {
    MallocBlockInfo info;
    info.file = file;
    info.line = line;
    info.len  = len;

    void* p   = malloc(len);
    
    if (NULL == p) {
        fprintf(stderr, "Failed to request memory!!!file:%s,line:%d\n", 
            file, line);
        p = NULL;
        goto Exit;
    }
    g_blockMap.insert(std::make_pair(p, info));
    g_blockSize++;
Exit:
    return p;
}

void FirstChoiceFree(void * p) {
    if (NULL == p) {
        return;
    }

    auto iter = g_blockMap.find(p);
    if (iter == g_blockMap.end()) {
        fprintf(stdout, "FirstChoiceFree: [%p] not find\n", p);
    }
    else {
        g_blockSize--;
        g_blockMap.erase(iter);
    }
    free(p);
    p = NULL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

示例

class Test{
    
}

int main() {
    Test* test = (Test*)FIRST_CHOICE_MALLOC(sizeof(Test));
    new(test) Test();
    
    test->~Test();			//跟malloc同理,free也不会调用类的析构函数,即我们应当显式调用
    FirstChoiceFree(test);
    test = NULL;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号