【问题标题】:delete vs explicit call of destructor [duplicate]删除与显式调用析构函数[重复]
【发布时间】: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 + free vs delete。那不一样...
  • @m8mble 如果问题在其他地方得到了回答,尽管另一个问题的提出方式不同,那么它是 IMO 重复的。虽然我们可能会争论它:)。但答案是一样的。顺便说一句,这两个问题都解决了同样的问题。不调用析构函数不一定是问题;参见,例如,Is it OK not to call the destructor on placement new allocated objects?

标签: c++ language-lawyer destructor


【解决方案1】:

虽然显式调用析构函数是合法的,但您想要这样做的情况非常少见(例如,std::vector 对象在更大的缓冲区中构造和析构)。

请注意,您应该始终将分配器与适当的内存释放、malloc/free、new/delete 等相匹配。虽然 operator new() 通常在底层依赖 malloc,但并不要求它这样做在这种情况下,您的不匹配将产生未定义的结果。

【讨论】:

    猜你喜欢
    • 2015-10-08
    • 2012-03-13
    • 2021-01-28
    • 2014-12-27
    • 2012-11-28
    • 2013-09-30
    • 1970-01-01
    相关资源
    最近更新 更多