【发布时间】:2019-06-09 05:50:38
【问题描述】:
在 C++ 中,对使用 new 分配的对象调用 delete 会调用类的析构函数,并释放内存。如果不是删除对象,而是显式调用其析构函数然后释放内存,会有什么不同吗?
考虑一下,例如,下面的例子。
#include <iostream>
struct A {
int i;
~A() { std::cout << "Destructor, i was " << i << std::endl; }
};
int main()
{
A* p = new A{3};
p->~A();
free(p);
return 0;
}
使用g++ 7.3.0 和clang 6.0.1 以及-Wextra -Wall -pedantic 编译代码不会引发任何警告。
正如预期的那样,程序的输出是
Destructor, i was 3
使用valgrind/memcheck 运行程序会出现释放/删除不匹配的错误:
==27743== Memcheck, a memory error detector
==27743== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27743== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==27743== Command: ./destructor
==27743==
Destructor, i was 3
==27743== Mismatched free() / delete / delete []
==27743== at 0x4C3033B: free (vg_replace_malloc.c:530)
==27743== by 0x4009FC: main (in /tmp/destructor)
==27743== Address 0x5bbac80 is 0 bytes inside a block of size 4 alloc'd
==27743== at 0x4C2F77F: operator new(unsigned long) (vg_replace_malloc.c:334)
==27743== by 0x4009DA: main (in /tmp/destructor)
==27743==
==27743==
==27743== HEAP SUMMARY:
==27743== in use at exit: 0 bytes in 0 blocks
==27743== total heap usage: 3 allocs, 3 frees, 73,732 bytes allocated
==27743==
==27743== All heap blocks were freed -- no leaks are possible
==27743==
==27743== For counts of detected and suppressed errors, rerun with: -v
==27743== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
但是,没有内存泄漏。
我当然知道在上面的代码中处理对象p 的标准方法是调用delete。
我的问题比较正式:
-
delete完全等同于调用析构函数和free?标准是否指定了这一点,或者我遇到了 UB 用上面的代码?
【问题讨论】:
-
如果
malloc()、calloc()或realloc()未返回该指针,则将非空指针传递给free()会产生未定义的行为。因此,您对free()的调用具有未定义的行为。 -
@francesco 但是您的问题也有很多答案。例如,请参阅我之前的带有复制粘贴链接的评论。根本无法保证
new使用malloc/calloc/realloc。 -
@DanielLangr 我不认为这是重复的。这个问题知道 dtor,但要求 dtor +
freevsdelete。那不一样... -
@m8mble 如果问题在其他地方得到了回答,尽管另一个问题的提出方式不同,那么它是 IMO 重复的。虽然我们可能会争论它:)。但答案是一样的。顺便说一句,这两个问题都解决了同样的问题。不调用析构函数不一定是问题;参见,例如,Is it OK not to call the destructor on placement new allocated objects?。
标签: c++ language-lawyer destructor