- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我不明白“删除”运算符在 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->left
和a->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++ 中,如果 class
、struct
或 union
没有用户声明的析构函数,则编译器将始终隐式声明一个简单的析构函数。也就是说,尽管您尚未为 Node
类声明析构函数,但 C++ 标准要求编译器为您声明一个简单的析构函数。
一旦您的类使用了odr,就会定义这个隐式声明的简单析构函数。也就是说,当程序中任何位置的任何表达式获取类的对象的地址或直接将引用绑定(bind)到类的对象时。
对先前使用 new
分配的 Node
对象调用 delete
将调用其隐式定义的析构函数以及为该对象分配的堆存储空间new
将被回收(即释放)。
由于隐式声明的析构函数很简单,因此成员指针 left
和 right
指向的任何存储都不会被触及。这意味着,如果您分配了仅由 Node
对象的 left
和 right
成员指针指向的任何内存。在此对象上调用删除后,成员指针 left
和 right
所指向的内存将成为孤立的(即,您将出现内存泄漏)。
核心机器级别发生的情况可能因供应商、操作系统和机器而异,因为 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
, andoperator delete[]
. [ Note: The implicit declarations do not introduce the namesstd
,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/
渐进增强和优雅降级基本是一回事吗? 最佳答案 不完全是。他们从不同的 Angular 解决类似的问题。 “优雅的降级”意味着你有漂亮的功能,并且可以在不支持它的浏览器中处理它不那么漂亮(但仍然需要它以
在过去的几周里,我一直在调优和处理 PostgreSQL,我将在我的下一个项目中使用它。 我的规范是: DigitalOcean 8 核 16GB SSD x2(一个用于数据库,另一个用于 Web)
我看过很多关于负数模的问题的答案。每一个答案都放了标准 (a/b)*b + a%b is equal to a 解释。我可以用这种方法计算任何模数,而且我知道有必要使用一个模数函数,如果它是负数,则将
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
The docs假设所有标签都存储在 .hgtags 中,但这里显然存在一些黑魔法。 我的标签如下所示: mbayazit:~/test$ cat .hgtags 0d80b6ba4ba3b51a44
我正在尝试强制删除待处理的更改列表。所有文件(20 个旧文件)都是新文件,但尚未提交/提交。所以在 p4Win 中,它们显示红色 + 十字。我无法从更改列表中删除这些文件。我该如何删除这些文件? 感谢
如果我要删除的文件不属于工作区,那么如何从工作区的目录中删除文件? 我的文件系统上有一个目录,其中包含从 perforce 获取的文件,但在某些进程运行后,它会在这些目录中创建一些新文件。 是否有 p
就是好奇这个。以下是同一功能的两个代码片段: void MyFunc1() { int i = 10; object obj = null; if(something) ret
我对使用约束布局还很陌生,我在调整布局大小方面遇到了问题,我希望它能够响应,这样我就不必再为不同的屏幕尺寸制作 10 个布局。在布局编辑器中,一切在不同尺寸下看起来都很完美,但实际上并非如此。 我做了
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
如果试图修改声明为 const 的对象,const 类型限定符会导致编译器发出错误消息,但这还不够保护。例如以下程序修改声明为 const 的数组的两个元素: #include int main(v
我不得不问这个,因为:我唯一知道的是,如果断言失败,应用程序就会崩溃。这就是为什么要使用 NSAssert 的原因吗?或者这样做还有什么好处?将 NSAssert 置于我在代码中所做的任何假设之上是否
我正在处理我的操作系统项目的 POSIX 子系统,并且我已经达到了我想要处理 pthreads 支持的地步。但是,我不确定我应该在多大程度上实现它们。 最常用的 pthreads 功能是什么?现在有什
这个问题不太可能对任何 future 的访客有帮助;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于互联网的全局受众。如需帮助使这个问题更广泛适用,visit the h
我正在尝试运行测试类,但抛出错误实际上有零交互。 class Xtractor{ void extractValues(request,Map m1, Map m2,Map m3){
我有一个抽象类UIObject,如下所示: public abstract class UIObject { private final int tabOrder; public UI
这是我尝试在 emacs lisp 中进行一些计算时得到的... (+ 2082844800. 1274511600.0) => 1209872752.0 (+ 2082844800.0 127451
我想用一条垂直线将屏幕分成两部分。垂直线应该从屏幕底部一直延伸到导航栏。如果我们使用 html/css,我只会有 2 个 div,并在右侧 div 上放置一个左边框。如果有办法在 View 的单侧放置
我有一个EC2实例可以正常工作数月(仍在开发中,应用程序尚未启用),但是我只是意识到我什至不知道如何根据流量来扩大/缩小EC2实例。 亚马逊提供的大量服务是压倒性的,我对此感到非常困惑。 最初,虽然我
考虑这个代码: int i = 1; int x = ++i + ++i; 我们对编译器可能会为这段代码做些什么有一些猜测,假设它可以编译。 两者 ++i返回 2 ,导致 x=4 . 一 ++i返回
我是一名优秀的程序员,十分优秀!