当前位置: 首页 > news >正文

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();

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;
}

nothrow new

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

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

void operator delete(void*) throw();

实例

#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;
}

palacement new

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

void* operator new(size_t, void*);

void operator delete(void*, void*);

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;
}

其他

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;
}

注意点

  在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;
}

效果图

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

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;
}

效果图

应用

  在我们使用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);

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;
}

示例

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;
}

相关文章:

  • 网站建设咋打开自己网站主页网址/贺贵江seo教程
  • wordpress产品分类插件/网站建设外包
  • 博罗营销网站制作/手机上可以创建网站吗
  • 深圳民治网站建设/网站关键词优化排名软件系统
  • 如何做好网站建设和宣传/黑帽seo之搜索引擎
  • 海南发展/网站查询seo
  • 机器学习SVM算法原理
  • 微信小程序自定义获取手机号按钮样式
  • 【C++】继承、多态、抽象类
  • (附源码)计算机毕业设计SSM基于JAVA线上订餐系统
  • 使用分布式锁 解决订单超卖场景(二)
  • 【前端知识】vue的生命周期
  • Excel - 学习 - 笔记4: Excel 函数 - if 函数
  • 神经网络是一种算法吗,神经网络包括哪些算法
  • 分享13个游戏源代码总有一个是你想要的
  • 自动调节式防涝井盖设计
  • 【湍流】基于kolmogorov结合次谐波补偿的方法生成大气湍流相位屏附matlab代码
  • 网络安全观察攻击类型分布