谁定义了新的运营商?

时间:2017-09-01 03:06:46

标签: c++ new-operator dynamic-memory-allocation

这个程序应该编译吗?

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>在这一切中的作用是什么?

2 个答案:

答案 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";
}

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