gpt4 book ai didi

c++ - 关于operator new()和operator delete()的问题

转载 作者:行者123 更新时间:2023-11-30 02:07:04 25 4
gpt4 key购买 nike

考虑以下代码和以下问题:

/*
* GCC 4.4
*/
#include <iostream>

using namespace std;

class A {
public:

void* operator new(size_t s) {
cout << "A::operator new(size_t) called\n";
}

void operator delete(void* p) {
cout << "A::operator delete(void*) called\n";
}

void* operator new(size_t s, A* p) {
cout << "A::operator new(size_t, A*) called\n";
}

void operator delete(void* p, size_t s) {
cout << "A::operator delete(void*, size_t) called\n";
}

};

void* operator new(size_t s) {
cout << "::operator new(size_t) called\n";
}

void operator delete(void* p) {
cout << "::operator delete(void*) called\n";
}

void* operator new(size_t s, A* p) {
cout << "::operator new(size_t, A*) called\n";
}

void operator delete(void* p, size_t s) {
cout << "::operator delete(void*, size_t) called\n";
}

int main() {
A* p1 = new A(); // See question 1.
delete p1; // See question 2.
A* p2 = new (p1) A(); // See question 3.
delete p2; // See question 4.
}

以下问题不知何故似乎有些多余。但是,我试图区分 C++ 标准规则定义的内容与实现定义的内容。

  1. operator new(size_t) 将在任何情况下使用(取自 A 或全局 命名空间,无论是否默认)。还行吧。 现在尝试仅删除 void* A::operator new(size_t) {}:为什么编译器给出:

    error: no matching function for call to ‘A::operator new(unsigned int)’ note: candidates are: static void* A::operator new(size_t, A*)

    Connot 编译器从全局中获取 ::operator new(size_t) 命名空间?

  2. 为什么 operator delete(void*) 优于 operator delete(void*, size_t) (当这两个版本都存在于 operator delete (void*) 所在的同一个命名空间中时)?

  3. 如果我删除 void* A::operator new(size_t, A*),为什么代码无法编译, 尽管在全局命名空间中定义了相同版本的运算符?

    error: no matching function for call to ‘A::operator new(unsigned int, A*&)’ note: candidates are: static void* A::operator new(size_t)

  4. 为什么编译器还是喜欢 operator delete (void*),尽管使用了A::operator new(size_t, A*) 为了获得 p2?

最佳答案

让我们想象一些场景。首先,以下始终有效:

A * p1 = ::new A;
::delete p1;

A * p2 = ::new (addr) A; // assume "void * addr" is valid
p2->~A();

全局表达式总是使用全局命名空间中的相应运算符,所以我们没问题。请注意,没有“放置-删除”表达式。每个放置构造的对象必须通过调用析构函数显式销毁。

接下来,假设我们写:

A * p3 = new A;
delete p3;

这一次,首先在A 的作用域中查找分配函数operator new(size_t)。该名称存在,但如果删除正确的重载,则会出现错误。 (这回答了问题 1 和问题 3。)operator delete() 也是如此。单参数版本 ((void *)) 优于双参数版本 ((void *, size_t)) 并没有特别的原因;你应该只有两者之一。 (另请注意,双参数函数没有全局版本。)

最后,让我们重新审视 placement-new 表达式。由于没有放置-删除表达式,您的最后一行代码是一个错误(未定义的行为):您不能删除任何不是通过默认获取的内容- 表达式。如果你定义了一个 placement-new 分配函数,你也应该定义匹配的释放函数。不过,此函数只会在一种特定情况下自动调用:如果放置新表达式 new (a, b, c) Foo; 导致构造函数抛出异常,然后 相应的释放函数被调用。否则,由于所有放置构造都是手动的,您通常只会手动调用放置释放函数(通常根本不会调用,因为它很少做任何实际工作)。

典型的场景可能是这样的:

void * addr = ::operator new(sizeof(Foo)); // do real work

Foo * p = new (addr, true, 'a') Foo; // calls Foo::operator new(void*, bool, char);,
// then calls the constructor Foo::Foo()

// in case of exception, call Foo::operator delete(addr, true, 'a')

p->~Foo();

Foo::operator delete(addr, true, 'a'); // rarely seen in practice, often no purpose

::operator delete(addr); // do real work

回到开头的代码示例,请注意标准要求全局 ::operator delete(void *, void *) 什么都不做。即要求global placement-new需要零清理。

关于c++ - 关于operator new()和operator delete()的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8220100/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com