IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ new的三种用法 -> 正文阅读

[C++知识库]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;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:13:43  更:2022-10-17 12:14:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 8:02:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码