【问题标题】:Destructor in template class c : How to delete field which may be pointer or not pointer?模板类 c 中的析构函数:如何删除可能是指针或不是指针的字段?
【发布时间】:2012-10-12 10:21:06
【问题描述】:

我有模板类Array,其中模板类型T 应该是指针或非指针类型。

template<class T>
class TArray
{   
     static const int max_len=100;
     T* data;
     int length;

  public:
     TArray(){data=new T[max_len]; this->length=0;} 
     void Add(T value){data[length++]=value;}   
     ~TArray();
};

问题是如何释放空间,因为我们不能调用delete 来处理非指针类型

template<class T>
TArray<T>::~TArray()
{
    //for(int i =0; i < length; i++)
    //  delete data[i]; // NOT WORKING WITH OBJECTS THAT ARE NOT POINTERS !!!
    delete[] data;
}

让我们有加法类

class A
{
    int* a;
  public:
    A(int n){a = new int[n];}
    ~A(){delete[] a;}
};

并创建模板类的两个实例

// Create array of doubles
TArray<double>* double_array = new TArray<double>();
delete double_array;

// Create array of pointers to class A
TArray<A*>* A_array = new TArray<A*>();
A* a = new A(5);
A_array->Add(a);
delete A_array;

当我为 TArray&lt;A*&gt; 调用析构函数时,我需要为类 A 调用析构函数,但我不知道如何,因为如果我们制作例如双精度数组,析构函数中的注释代码不会编译 (C2541)。

【问题讨论】:

  • 你为什么newing 一切都在眼前?必须如此随意地使用new 的代码几乎总是存在一些设计缺陷。
  • 如果您的类的用户想要创建一个指针数组,该数组指向未使用new 分配的数据,例如字符串文字?他们不走运,就是这样。出于这个原因,您可能应该将您的类 not 设计为在其析构函数中的每个元素上调用 delete。如果用户想要这种行为,那么他们可以通过创建一个TArray&lt;T&gt; 来获得它,其类型为T,其中包含一个指针并在其析构函数中将其删除。事实上,您的班级 A 就是这样做的。
  • @Praetorian:我认为你甚至可以说代码中存在当然一个设计缺陷,它使用new 分配像TArray 这样的小类型,然后将其删除相同的范围。也许一个 Java 程序员还没有意识到在 C++ 中你可以有一个类类型的变量(即不是指针也不是内置的算术类型)?
  • @Steve Jessop 感谢您提供有用的评论,即数据可能未分配新的数据,如果我尝试删除每个元素会产生问题。我是 C# 程序员,所以这可能是我 newing 一切的原因。但是,我看不出这有什么问题,我在任何地方都使用和传递指针,并避免使用复制构造函数。在我看来,除了为指针而不是指针类型创建两个类之外,没有解决方案。
  • @Petar:您可能需要将指针的概念、指针指向的内存如何分配的概念以及指针。它们是不同的东西。即使您确实为指针和非指针类型编写了不同的类,您仍然不能delete[] 指向字符串文字的指针。并且您可以将指针传递给局部变量,前提是指针不会超过变量的寿命——您不需要使用new 来避免复制。

标签: c++ templates destructor


【解决方案1】:

如果用std::unique_ptrstd::shared_ptr 替换原始指针,问题就消失了。

(如果这不是您想要的,那么请三思而后行是否应该由TArray 来管理它。谁会保证存储在TArray&lt;T*&gt; 中的指针已经分配给new?没有@987654321 @解决这个问题。)

【讨论】:

  • 为什么是shared_ptr?我想说unique_ptr 应该始终是您的首选,除非您真的想共享托管对象。
  • @Praetorian: shared_ptr 在容器中使用确实比unique_ptr 有一个潜在优势,那就是删除函数的类型是unique_ptr 类型的一部分,但不是shared_ptr。因此,如果您想要一个包含完全不同删除器的指针容器,即使对象未共享,这也可能是使用 shared_ptr 的充分理由。当然,对于这种简单的情况,提问者需要默认删除器。
【解决方案2】:

在析构函数内部,您可以使用std::is_pointer,然后只能使用delete[] 数据。

首选的替代方法是不要自己管理内存(使用std::vector 或智能指针)。

【讨论】:

    【解决方案3】:

    您可以为您的模板开发两个版本。首先写普通版template&lt;class T&gt;。然后,编写第二个仅指针版本,特化您的模板,如下声明:

    template<class T>
    class TArray<T*>
    

    【讨论】:

    • 我实现了这个解决方案。从抽象类派生这两个类,因为它们包含相同的代码,而派生的类只有不同的析构函数。
    • 很高兴能帮上忙 :) 不要忘记接受您选择的答案
    猜你喜欢
    • 2018-03-24
    • 2018-09-12
    • 2014-05-15
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    相关资源
    最近更新 更多