【问题标题】:How to know when to call delete and when delete[] in C++?如何知道在 C++ 中何时调用 delete 以及何时调用 delete[]?
【发布时间】:2020-10-14 06:42:39
【问题描述】:

我正在实现类 my_unique_ptrmy_shared_ptr,它们模仿标准库智能指针 std::unique_ptrstd::shared_ptr,以便更好地了解它。

在实现析构函数时,我很难决定是使用delete 还是delete[] 来释放内存。就我在 SO 和其他网站上阅读的内容而言,没有可移植的方式知道new[] 分配了多少字节(或者是使用了new 还是new[])(@987654321 @)

在实现类my_unique_ptr时,我无法知道用户将从构造函数请求多少字节,即

他会不会做my_unique_ptr<int> ptr1(new int)

或者他会做 my_unique_ptr<int> ptr1(new int[5])

如果有办法请告诉我!

这是我的类(简化且没有 cpy/move 构造函数):

template<typename ValueType>
class my_unique_ptr {

    ValueType *internal_ptr = nullptr;

public:
    
    // Default constructor
    my_unique_ptr() {
       internal_ptr = nullptr;
    }

    // Paramterized constructor
    explicit my_unique_ptr(ValueType *ptr) {
       if (ptr)
        internal_ptr = ptr;
    }

    // Destructor
    ~my_unique_ptr() {
       
        // How do I know whether to use
           delete ptr;

        // or
           delete[] ptr;
        
     }

我在某处读到编译器跟踪new[] 的参数,然后delete[] 使用该参数来正确释放内存。另请阅读“程序员有责任将newdeletenew[]delete[] 匹配”。但是我如何在我的班级中对此进行编程,以使其始终匹配正确的运算符?

旁注:

运行valgrind,同时在任何地方使用delete而不是delete[],并在我的构造函数中传递超过1个int(比如new int[5]),Valgrind说所有内存块都被释放了,没有机会泄漏! (虽然显示像mismatched new[] with delete 这样的警告。这是否意味着delete 正在成功释放new[] 分配的所有5 个ints?请帮助。 我在Ubuntu 18.04 并使用gcc 7.5.0

【问题讨论】:

  • 最简单的就是专门化my_unique_ptr&lt;T[]&gt;,然后要求用户使用my_unique_ptr&lt;int[]&gt; ptr1(new int[5]);。这就是标准库智能指针的作用。
  • @cdhowie 我明白了,谢谢!
  • @cdhowie 有趣的是,一旦你用你的回复摧毁他们,这里的每个人都会删除他们的答案xD
  • @SirajQazi 大声笑我得到了类似的回复,但是,我的也是有效的解决方案!所以我不会删除那个..
  • @K.R.Park 哈哈当然,也谢谢你回答我的问题:)

标签: c++ memory-management new-operator smart-pointers delete-operator


【解决方案1】:

您是正确的,您无法知道内存是由new 还是new[] 分配的。但是你甚至不知道内存存储了一个自动持续时间对象。例如。您的用户可以这样做:

int a = 24;

my_unique_ptr<int> ptr1(&a); // oups

你无法知道这一点。所以做标准库的工作:

  • 对数组类型进行专门化,例如template &lt;class T&gt; class my_unique_ptr&lt;T[]&gt; 在析构函数上调用 delete[]

  • 要求my_unique_ptr&lt;T&gt; 必须使用从new 获得的内存进行初始化,my_unique_ptr&lt;T[]&gt; 必须使用从new[] 获得的内存进行初始化。这是您图书馆的用户必须遵守的合同。如果不尊重,那就是UB。

  • 通过提供std::make_unique 的等价物来帮助用户遵守本合同。另见Advantages of using std::make_unique over new operator


这是否意味着 delete 成功释放了 new[] 分配的所有 5 个整数

没有。在不是从new 获得的内存上调用delete 是UB。

【讨论】:

  • 我明白了。非常感谢你清除这个!我想我没有想到 &lt;T[]&gt; 的另一个模板专业化的可能性,所以我不知道编译器如何使运算符正确匹配。再次感谢你:)
【解决方案2】:

实际上,标准库智能指针比您的代码具有额外的功能,它们能够在调用其析构函数时使用什么运算符(delete 或 delete[])。它们默认采用 delete,如果你想使用 delete[],你应该将它提供给智能指针构造函数。除此之外,如果您创建单个对象,请使用 new 和 delete。如果你创建一个数组,使用 new[] 来删除它,使用 delete[] 来删除它。

【讨论】:

  • 您根本不必使用自定义删除器,只需使用例如std::unique_ptr&lt;int[]&gt;T[] 有一个专门化使用 delete[]
  • @cdhowie 我完全不知道这种解决方案。一个很好的学习点。谢谢。
  • 是的,这一切都很好,我明白了,但我不知道用户是要创建单个对象还是数组,这就是我问的。无论如何,我从@bolov 和 cdhowie 得到了答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2020-06-03
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多