【问题标题】:delete vs delete[] in destructor析构函数中的 delete vs delete[]
【发布时间】:2020-06-22 23:59:13
【问题描述】:

我在学习 C++ 考试 我被问到在这段代码中,类的 d'tor 是否应该使用 delete[] 而不是 delete:

    template <class T>
class ClonePtr
{
private:
    T* ptr;
public:
    explicit ClonePtr(T* p = nullptr) : ptr(p) {}
    ~ClonePtr() { if(ptr!=nullptr) delete []ptr; }
    ClonePtr(const ClonePtr& other) : ptr(nullptr)
    {
        *this = other;
    }
    ClonePtr(ClonePtr&& other) : ptr(other.ptr)
    {
        other.ptr = nullptr;
    }
    ClonePtr& operator=(const ClonePtr& other)
    {
        if (this != &other)
        {
            delete ptr;
            if (other.ptr != nullptr)
                ptr = other.ptr->clone();
        }
        return *this;
    }
    T& operator*() const { return *ptr; }
};

这个问题的正确答案是肯定的, 但这是为什么呢?

+关于这段代码我还有两个小问题:

  1. 考试中说T型必须是类,不能是原始类型。 这是为什么呢?
  2. 另一方面,我尝试编写以下代码:
A级 { 私人的: 诠释 x; 上市: A(int x = 8) : x(x) { }; }; 主函数() { ClonePtr h(新 A(7)); }

并得到一个编译器错误:C2664“无法将参数 1 从 A* 转换为 T*”

非常感谢您的帮助。

谢谢:)

【问题讨论】:

  • 这是一个糟糕的课程。它不分配任何内存,为什么会删除内存,更不用说delete[]
  • 没有分配数组的指示。因此使用delete 而不是delete []delete[] 用于删除数组。
  • delete ptr 中的operator= 是故意的吗?如果是这种情况,并且问题是关于析构函数的,我会说它应该是delete(与另一个匹配)。
  • 这实际上是一个很好的例子,说明为什么你应该拒绝newdelete,无论它们是否是[] 版本,并坚持使用容器和智能指针。除非您确切知道某物是如何分配的,因为您分配了它,或者提供商的文档告诉您如何处置它,否则您不应该尝试释放它。它可能是malloced 或自动分配给所有你知道的。
  • ClonePtr&lt;int&gt; 将专注于 int。这意味着ClonePtr(T* p = nullptr) 将变为ClonePtr(int* p = nullptr)。并且想要一个指向int 的指针,而不是指向A 的指针。 ClonePtr&lt;A&gt; 将接受指向 A 的指针。

标签: c++ oop


【解决方案1】:

我们无法以一种或另一种方式肯定地回答这个问题,因为我们无法看到传递给ClonePtr(T*) 的指针类型,或者clone() 返回的指针类型。这个类没有做它自己的任何内存分配。

IF 两个指针都分配给new 而不是new[],那么delete 将是正确答案,而不是delete[]

IF 两个指针都分配给new[] 而不是new,那么delete[] 将是正确答案,而不是delete

就此而言,因为这段代码获取了由其他东西分配的内存的所有权,并且这个类使用nullptr 和移动构造函数(但不是移动赋值)很清楚运算符!),您使用的是 C++11 或更高版本,因此您应该通过std::unique_ptrstd::shared_ptr使用正确所有权语义,而不是使用原始指针完全没有。

特别是因为如果other.ptrnullptr,您的复制赋值运算符没有在delete ptr; 之后将ptr 设置为nullptr,从而使*this 处于错误状态。使用适当的所有权语义可以避免这种情况。

试试这个:


更新:现在您已经发布了附加代码(无法编译,因为不能将 A* 分配给 int*,并且 A 没有实现 @987654344 @) 显示ptr 被设置为分配有new 的对象,所以正确答案是:

  • 必须使用delete,而不是delete[]

所以你考试的“正确答案”是错误的。

但正确的所有权语义会更好,例如:

#include 

模板 
类 ClonePtr
{
私人的:
    std::unique_ptr ptr;

上市:
    ClonePtr(std::unique_ptr p) : ptr(std::move(p)) {}

    ClonePtr& operator=(ClonePtr 其他)
    {
        ptr = std::move(other.ptr);
        返回*这个;
    }

    T& operator*() const { return *ptr; }
};

A级
{
私人的:
    诠释 x;

上市:
    A(int x = 8) : x(x) { };

    std::unique_ptr clone() 常量
    {
        返回 std::make_unique(x);
        // 或:在 C++14 之前:
        // 返回 std::unique_ptr(new A(x));
    }
};

主函数()
{
    ClonePtr h(std::make_unique(7));
    // 或者,在 C++14 之前:
    // ClonePtr h(std::unique_ptr(new A(7)));
}

【讨论】:

  • 我还认为这次考试缺乏信息......我认为如果我们不知道指针是否指向单个对象或到一个数组..奇怪的问题。不过谢谢:)
  • 顺便问一下,你知道为什么这个类只能接收 T 类而不是原始类型吗?
  • 原始类型肯定会被拒绝,因为它们不可能实现clone,而类可以。
  • @Ta 好点。不过,对clone() 的调用可以使用std::is_trivially_copyable() 进行SFINAE 删除,因此原始类型可以按原样复制而不是克隆。
猜你喜欢
  • 1970-01-01
  • 2011-01-12
  • 2014-11-22
  • 2013-06-25
  • 2017-02-06
  • 2018-06-02
  • 2011-06-11
  • 2017-02-15
  • 2022-01-11
相关资源
最近更新 更多