首页 > 编程语言 >41.C++中有几种类型的new

41.C++中有几种类型的new

时间:2023-07-03 21:44:07浏览次数:36  
标签:std ADT void C++ 41 内存 new delete

41.C++中有几种类型的new

在C++中,new有三种典型的使用方法:plain new,nothrow new和placement new

(1)plain new

言下之意就是普通的new,就是我们常用的new,在C++中定义如下:

void* operator new (std::size_t size) throw (std::bad_alloc)  
{  
    void* ptr = std::malloc(size);  
    if (ptr == nullptr)  
        throw std::bad_alloc();  
    return ptr;  
}
void operator delete (void* ptr) throw ()  
{  
    std::free(ptr);  
}

因此plain new在空间分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,因此通过判断返回值是否为NULL是徒劳的,举个例子:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	try
	{
		char *p = new char[10e11];//这段代码会导致 std::bad_alloc 异常的抛出,因为请求分配的内存超出了系统所能提供的范围。
		delete p;
	}
	catch (const std::bad_alloc &ex)
	{
		cout << ex.what() << endl;
	}
	return 0;
}
//执行结果:bad allocation

(2)nothrow new

nothrow new在空间分配失败的情况下是不抛出异常,而是返回NULL,定义如下:

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

举个例子:

#include <iostream>
#include <string>
using namespace std;

int main()
{
	char *p = new(nothrow) char[10e11];
	if (p == NULL) 
	{
		cout << "alloc failed" << endl;
	}
	delete p;
	return 0;
}
//运行结果:alloc failed

3)placement new

这种new允许在一块已经分配成功的内存上重新构造对象或对象数组。placement new不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数。定义如下:

void* operator new(size_t,void*);
void operator delete(void*,void*);

使用placement new需要注意两点:

  • palcement new的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组
  • placement new构造起来的对象数组,要显式的调用他们的析构函数来销毁(析构函数并不释放对象的内存),千万不要使用delete,这是因为placement new构造起来的对象或数组大小并不一定等于原来分配的内存大小,使用delete会造成内存泄漏或者之后释放内存时出现运行时错误。

举个例子:

#include <iostream>
#include <string>
using namespace std;
class ADT 
{
	int i;
	int j;
public:
	ADT()
	{
		i = 10;
		j = 100;
		cout << "ADT construct i=" << i << "j=" << j << endl;
	}
	~ADT() {
		cout << "ADT destruct" << endl;
	}
};

int main()
{
	char* p = new(nothrow) char[sizeof ADT + 1];
	if (p == NULL) {
		cout << "alloc failed" << endl;
	}
	ADT* q = new(p) ADT;  //placement new:不必担心失败,只要p所指对象的的空间足够ADT创建即可
	//delete q;//错误!不能在此处调用delete q;
	q->ADT::~ADT();//显示调用析构函数
	delete[] p;
	return 0;
}
//输出结果:
//ADT construct i=10j=100
//ADT destruct

在上述代码中,sizeof ADT + 1是为了确保分配的内存足够容纳一个 ADT 对象和一个指向 ADT 对象的指针。

首先,new(nothrow) char[sizeof ADT + 1] 语句使用 nothrow 关键字来分配一块内存,用于存储一个 char 类型的数组。这个数组的大小为 sizeof ADT + 1,其中 sizeof ADT 是获取 ADT 对象的大小,加 1 是为了给指针留下空间。

接下来,new(p) ADT 使用 placement newp 所指向的内存地址上构造一个 ADT 对象。这里使用了 placement new,因为它是在已经分配好的内存上构造对象,而不是在堆上分配内存。

由于这里是使用 placement new 构造的对象,因此不能直接使用 delete q 来释放内存,因为 placement new 不会调用析构函数来清理对象。为了显式地调用析构函数,可以使用 q->ADT::~ADT() 来调用析构函数进行清理。

最后,使用 delete[] p 来释放之前分配的内存块。由于这里使用了 new[],因此需要使用 delete[] 来释放整个数组。

参考资料来源:

阿秀

标签:std,ADT,void,C++,41,内存,new,delete
From: https://www.cnblogs.com/codemagiciant/p/17524188.html

相关文章

  • 24.C++中const和static的作用
    static●不考虑类的情况○隐藏。所有不加static的全局变量和函数具有全局可见性,可以在其他文件中使用,加了之后只能在该文件所在的编译模块中使用○默认初始化为0,包括未初始化的全局静态变量与局部静态变量,都存在全局未初始化区○静态变量在函数内定义,始终存在,且只进行一次初始......
  • 25.C++的顶层const和底层const
    任意常量对象为顶层const,包括常量指针;指向常量的指针和声明const的引用都为底层const  顶层const(top-levelconst)表示指针本身是个常量int*constptr=&m;  此时指针不可以发生改变,但是指针所指向的对象值是可以改变的  底层const(low-levelconst)表示指针所指的对象是常量......
  • 32.C和C++的类型安全
    什么是类型安全?类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域。“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制;有的时候也用“类型安全”形容某个程序,判别的标准在于该程序是否隐含类型错误。类......
  • 34.C++有哪几种的构造函数
    34.C++有哪几种的构造函数C++中的构造函数可以分为4类:默认构造函数:在没有显式定义构造函数时,C++会自动生成一个默认构造函数,该函数没有参数,不执行任何操作。初始化构造函数(有参数)拷贝构造函数:当使用现有对象初始化新对象时,拷贝构造函数被调用。它的语法是在函数声明时使用一......
  • 33.C++中的重载、重写(覆盖)和隐藏的区别
    (1)重载(overload)  重载是指在同一范围定义中的同名成员函数才存在重载关系。主要特点是函数名相同,参数类型和数目有所不同,不能出现参数个数和类型均相同,仅仅依靠返回值不同来区分的函数。重载和函数成员是否是虚函数无关。举个例子:classA{...virtualintfun();......
  • 【C++】关于常引用的问题 #什么是权限放大?权限放小?隐式或强制转换居然还有这一步?...#
    前言引用在c++中的使用非常常见,可以说是很重要的,引用的常引用相关的问题让很多人稍不留神就出错了,这里我们就来谈谈常引用的问题。关于权限关于权限有权限缩小和权限放大的问题,比如一个文件,当初它只有读的权限,而现在你给它再加个写的权限,这就是权限放大;又或当初它读,写的权限......
  • 8.new-delete操作与malloc-free的操作异同
    相同点●都可用于内存的动态申请和释放●new和malloc都可以分配指定大小的内存块,并且分配的内存都在堆上。●new和malloc的结果都返回一个指向已分配内存的指针。●都允许使用字面量作为参数来分配内存。不同点●前者是C++运算符,后者是C/C++语言标准库函数●new自动计算要......
  • 10.malloc和new的区别?
    malloc和free是标准库函数,支持覆盖;new和delete是运算符,支持重载。malloc仅仅分配内存空间,free仅仅回收空间,不具备调用构造函数和析构函数功能,用malloc分配空间存储类的对象存在风险;new和delete除了分配回收功能外,还会调用构造函数和析构函数。malloc和free返回的是void类型指针......
  • 9.new和delete是如何实现的?
    new的实现过程是:首先调用名为operatornew的标准库函数,分配足够大的原始为类型化的内存,以保存指定类型的一个对象;接下来运行该类型的一个构造函数,用指定初始化构造对象;最后返回指向新分配并构造后的的对象的指针delete的实现过程:对指针指向的对象运行适当的析构函数;然后通过调用......
  • 11.既然有了malloc-free,C++中为什么还需要new-delete呢?直接用malloc-free不好吗?
    malloc/free和new/delete都是用来申请内存和回收内存的。在对非基本数据类型的对象使用的时候,对象创建的时候还需要执行构造函数,销毁的时候要执行析构函数。而malloc/free是库函数,是已经编译的代码,所以不能把构造函数和析构函数的功能强加给malloc/free,所以new/delete是必不可少......