这个程序应该编译吗?
int main(){
double* p = new double[4];
delete[] p;
return 0;
}
(它使用GCC 7.1.1编译)
我之所以这样问是因为,我不确定是谁提供了operator new
的定义。
是语言吗?默认情况下是编译器#include
ing <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;
}
我在这做什么?
覆盖new
?重载new
?编译器的new
特殊(魔术)的定义是什么? (例如,如果未定义,则使用提供的语言)。
#include<new>
在这一切中的作用是什么?
答案 0 :(得分:3)
这里有一个new
表达式,实际调用operator new[]
void* operator new[]( std::size_t count );
编译器隐式声明每个翻译单元中的基本operator new
(由标准指定),请参阅cppreference documentation。
版本(1-4)在每个翻译单元中隐式声明,即使&lt;新&GT;标题不包括在内。
在您的第二个代码段中,您重载(从技术上讲,您实际上是替换)operator new
(不是覆盖,那是仅适用于虚拟功能),但您应该重载operator new[]
(请注意,如果不这样做,那么operator new[]
将会回到operator new
,所以从技术上讲,我相信您的代码没问题,但为了清楚起见,我只是重载数组版本。
答案 1 :(得分:1)
操作员new可能存在其他重载。您有标量和数组版本,这些版本都由编译器提供,可能由标准库提供,也可能由用户代码提供。
如果您自己编写(如果他们没有内置版本的签名)或者#include new,则会有额外的new(和delete)重载。如果您提供与内置签名匹配的运算符,那么它们将替换内置版本。谨防。 :)
人们包括的主要原因是
1)在用户提供的内存地址中构建对象
2)非投掷版本的新
当然,还有操作符删除重载,因为新/删除必须成对重载才能一起工作,否则几乎会发生某些破坏。如果您的operator new匹配内置签名,它将替换内置版本而不是重载。
请记住,“新表达”简单如下:
std::string myString = new std::string();
实际上分为两部分:1)分配内存(通过operator new),然后,2)在该内存中构造一个对象。如果成功,它将返回指向该对象的指针,如果失败,则清除构造的内容,释放已分配的内容,然后抛出。
当你重载operator new时,你只处理内存分配,而不是构造函数调用,并且该对象将在该运算符返回的任何地址中构造。对于正常的展示位置new,您可能会看到如下代码:
char myBuffer[1024]; // assume aligned; nobody needs more than 1024 bytes
std::string *ptr = new (myBuffer) std::string();
assert (ptr == &myBuffer);
new的额外参数是myBuffer地址,它由operator new立即返回,并成为构造对象的位置。断言应该通过,并显示字符串是在myBuffer 的字节中创建的。
在#including new之后也可以使用no-throw版本的new,它还为运算符使用了额外的参数:
char * buf = new (std::nothrow) char[MAX_INT];
if (buf) {
std::cout << "WHOA, you have a lot of memory!!!\n";
}
现在不是失败,而是返回一个空指针,所以你必须检查它。