谁定义新操作员

Who defines the new operator?

本文关键字:操作员 定义      更新时间:2023-10-16

这个程序应该编译吗?

int main(){
double* p = new double[4];
delete[] p;
return 0;
}

(它确实与GCC 7.1.1一起编译(

我之所以这么问,是因为我不确定是谁在提供operator new的定义。是语言吗?编译器默认是#include还是<new>

为了使这个问题更加清楚,我实际上可以定义(覆盖?(运算符new

#include<cstdlib> // malloc and size_t
#include<cassert> // assert
void* operator new[](unsigned long int sz){ // what if this is not defined? who provides `new`?
assert(0); // just to check I am calling this function
return std::malloc(sz);
}
int main(){
double* p = new double[4]; // calls the new function above
delete[] p;
return 0;
}

我在这里干什么?

是否覆盖newnew过载?new的定义对编译器来说是特别的(神奇的(吗?(例如,如果未定义,则使用提供的语言(。#include<new>在这一切中的作用是什么?

这里有一个new表达式,它实际上调用operator new[]

void* operator new[]( std::size_t count );

编译器在每个翻译单元中隐式声明基本的operator news(这是由标准指定的(,请参阅cpprreference文档。

版本(1-4(在每个翻译单元中被隐式声明,即使<不包括new>标头

在您的第二个代码片段中,您正在重载(从技术上讲,您实际上是在替换(operator new(而不是覆盖,这仅用于虚拟函数(,尽管您应该重载operator new[](注意,如果您不重载,那么operator new[]将回到operator new,所以从技术上讲,我相信您的代码是可以的,但为了清晰起见,我只是重载数组版本(。

运算符new可能存在其他重载。标量和数组版本都是由编译器提供的,可能是由标准库提供的,也可能是由用户代码提供的。

如果你自己写(如果它们没有内置版本的签名(或者如果你#包含new,则会有额外的new(和delete(重载。如果您提供了与内置签名匹配的运算符,那么它们将替换内置版本。小心。:(

人们包括的主要原因是

1( 在用户提供的存储器地址中构造对象

2( 新的非投掷版本

当然,也存在运算符删除重载,因为新的/delete必须成对重载才能协同工作,否则几乎肯定会发生破坏。如果您的操作员new与内置签名匹配,它将替换而不是重载内置版本。

记住,一个简单的"新表达":

std::string myString = new std::string();

真正的工作分为两部分:1(分配内存(通过操作符new(,然后,2(在内存中构造一个对象。如果成功,它将返回指向该对象的指针;如果失败,它将清理构建的内容,释放分配的内容,然后抛出。

当您重载运算符new时,您只处理内存分配,而不是构造函数调用,并且对象将在该运算符返回的任何地址中构造。对于新的正常放置,你可能会看到这样的代码:

char myBuffer[1024];  // assume aligned; nobody needs more than 1024 bytes
std::string *ptr = new (myBuffer) std::string();
assert (ptr == &myBuffer);

new的额外参数是myBuffer地址,它由操作符new立即返回,并成为构建对象的地方。断言应该通过,并显示字符串是在myBuffer的字节中创建的。

new的无抛出版本在#included new之后也可用,它还使用了一个额外的运算符参数:

char * buf = new (std::nothrow) char[MAX_INT];
if (buf) {
std::cout << "WHOA, you have a lot of memory!!!n";
}

现在,它不会失败,而是返回一个空指针,所以你必须检查它