gpt4 book ai didi

c++ - 'delete' 运算符在 C++ 动态内存分配(堆)的幕后实际上是如何工作的?

转载 作者:行者123 更新时间:2023-12-01 23:07:57 25 4
gpt4 key购买 nike

我不明白“删除”运算符在 C++ 中是如何在幕后实际实现的。例如:

class Node{
int i;
Node *left,*right;
};

int main() {
Node* a = new Node; // somehow the object 'a' is initialised with its data members
delete a;
}

delete a; 在幕后究竟做了什么?就像是是否调用了任何默认析构函数或什么?另外,由于a包含左指针和右指针,那么对象a->lefta->right是否也被删除了?核心机器级别会发生什么?

最佳答案

命名法

根据 C++ 标准§12.4 Destructors/p4,p6,p7,p8,p12 [class.dtor](强调我的):

4 If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (8.4). An implicitly declared destructor is an inline public member of its class.

6 A destructor is trivial if it is not user-provided and if:

(6.1) — the destructor is not virtual,

(6.2) — all of the direct base classes of its class have trivial destructors, and

(6.3) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

Otherwise, the destructor is non-trivial.

7 A destructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) or when it is explicitly defaulted after its first declaration.

12 A destructor is invoked implicitly

(12.1) — for a constructed object with static storage duration (3.7.1) at program termination (3.6.4),

(12.2) — for a constructed object with thread storage duration (3.7.2) at thread exit,

(12.3) — for a constructed object with automatic storage duration (3.7.3) when the block in which an object is created exits (6.7),

(12.4) — for a constructed temporary object when its lifetime ends (4.4, 12.2). In each case, the context of the invocation is the context of the construction of the object. A destructor is also invoked implicitly through use of a delete-expression (5.3.5) for a constructed object allocated by a new-expression (5.3.4); the context of the invocation is the delete-expression. [ Note: An array of class type contains several subobjects for each of which the destructor is invoked. — end note ] A destructor can also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in 5.3.4, 12.6.2, and 15.1. A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.

博士;TL

在 C++ 中,如果 classstructunion 没有用户声明的析构函数,则编译器将始终隐式声明一个简单的析构函数。也就是说,尽管您尚未为 Node 类声明析构函数,但 C++ 标准要求编译器为您声明一个简单的析构函数。

一旦您的类使用了odr,就会定义这个隐式声明的简单析构函数。也就是说,当程序中任何位置的任何表达式获取类的对象的地址或直接将引用绑定(bind)到类的对象时。

对先前使用 new 分配的 Node 对象调用 delete 将调用其隐式定义的析构函数以及为该对象分配的堆存储空间new 将被回收(即释放)。

由于隐式声明的析构函数很简单,因此成员指针 leftright 指向的任何存储都不会被触及。这意味着,如果您分配了仅由 Node 对象的 leftright 成员指针指向的任何内存。在此对象上调用删除后,成员指针 leftright 所指向的内存将成为孤立的(即,您将出现内存泄漏)。

核心机器级别发生了什么

核心机器级别发生的情况可能因供应商、操作系统和机器而异,因为 C++ 标准未指定删除表达式的核心行为。只要可观察的行为符合 C++ 标准,任何编译器供应商都可以做任何想做的事情(例如,优化)。

不过,供应商或多或少也在做类似的事情。例如,让我们考虑以下代码:

class Node {
int i;
Node *left, *right;
};

int main() {
Node *n = new Node;
delete n;
}

上述代码为 GCC 6.2 版本编译器生成的汇编代码为:

main:
push rbp
mov rbp, rsp
sub rsp, 16
mov edi, 24
call operator new(unsigned long)
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
mov esi, 24
mov rdi, rax
call operator delete(void*, unsigned long)
mov eax, 0
leave
ret

在为我们的简单示例生成的汇编代码中,n 对象的构造由下面的代码片段表示:

sub     rsp, 16
mov edi, 24
call operator new(unsigned long)
mov QWORD PTR [rbp-8], rax

由于该对象是可简单构造的,因此编译器所做的唯一事情就是通过调用隐式声明的全局运算符new为该对象分配内存。

对象的销毁过程由下面的代码片段表示:

rax, QWORD PTR [rbp-8]
mov esi, 24
mov rdi, rax
call operator delete(void*, unsigned long)

请注意,销毁过程是按照与构造过程中所采取的步骤相反的顺序完成的。最后,调用隐式声明的全局运算符delete来释放先前分配的内存。

在我们的示例中,构造函数和析构函数都没有被调用,因为在我们的例子中,如果不调用它们,程序的可观察行为就不会改变。

现在正确的问题是 operator delete 到底在哪里?

为了保留这个答案的命名风格,让我们引用§3.7.4动态存储持续时间[basic.stc.dynamic]\p1, p2中的C++标准(强调我的):

1 Objects can be created dynamically during program execution (1.9), using new-expressions (5.3.4), and destroyed using delete-expressions (5.3.5). A C++ implementation provides access to, and management of, dynamic storage via the global allocation functions operator new and operator new[] and the global deallocation functions operator delete and operator delete[]. [ Note: The non-allocating forms described in 18.6.2.3 do not perform allocation or deallocation. — end note ]

2 The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation functions are replaceable (18.6.2). A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. Any such function definition replaces the default version provided in the library (17.5.4.6). The following allocation and deallocation functions (18.6) are implicitly declared in global scope in each translation unit of a program.

void* operator new(std::size_t); 
void* operator new(std::size_t, std::align_val_t); void operator delete(void*) noexcept;
void operator delete(void*, std::size_t) noexcept;
void operator delete(void*, std::align_val_t) noexcept;
void operator delete(void*, std::size_t, std::align_val_t) noexcept;
void* operator new[](std::size_t);
void* operator new[](std::size_t, std::align_val_t);
void operator delete[](void*) noexcept;
void operator delete[](void*, std::size_t) noexcept;
void operator delete[](void*, std::align_val_t) noexcept;
void operator delete[](void*, std::size_t, std::align_val_t) noexcept;

These implicit declarations introduce only the function names operator new, operator new[], operator delete, and operator delete[]. [ Note: The implicit declarations do not introduce the names std, std::size_t, std::align_val_t, or any other names that the library uses to declare these names. Thus, a new-expression, delete-expression or function call that refers to one of these functions without including the header is well-formed. However, referring to std or std::size_t or std::align_val_t is ill-formed unless the name has been declared by including the appropriate header. — end note ] Allocation and/or deallocation functions may also be declared and defined for any class (12.5).

答案是删除运算符在程序的每个翻译单元的全局范围内隐式声明。

关于c++ - 'delete' 运算符在 C++ 动态内存分配(堆)的幕后实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42325978/

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