删除模板类型

Deleting a Template Type

本文关键字:类型 删除      更新时间:2023-10-16

我有一个泛型类,看起来像这样:

template <class T>
class Example
{
  private:
    T data;
  public:
    Example(): data(T())
    Example(T typeData): data(typeData) 
    ~Example()
    // ...
};

我对如何为这样的事情实现解构器有点困惑。具体来说,由于T是任何类型的,它可以是在堆栈上分配的内存(通过无参数构造函数创建的Example总是如此)或堆上分配的内存。

例如,如果客户端将 T 的类型设为int*并提供指向动态内存的指针,我怎么知道在data上调用delete,而不是客户端是否将类型设置为 int

最简单的答案是:不要。不要试图对用户进行事后猜测并做一些他们可能意想不到的事情。采用与标准容器相同的策略:假设T正确清理自身。

如果客户端代码编写正确,它将使用 RAII 类(如智能指针)自动和正确管理内存和其他资源。如果不是,则不能希望在提供程序代码中解决此问题。

让您的班级与std::unique_ptrstd::shared_ptr以及任何其他自定义 RAII 类一起工作,并让您的客户自己进行管理。毕竟,如果他们想存储非拥有的指针怎么办?

您可以使用模板专业化。

template <class T>
class Example
{
  private:
    T data;
  public:
    Example()
        : data(T())
    {}
    Example(T typeData): data(typeData)
    {}
};
template <class T>
class Example<T*>
{
  private:
    T* data;
  public:
    Example() : data(nullptr){}
    Example(T* typeData): data(typeData) {}
    ~Example()
    {
        delete data;
    }
};
int main() 
{
    Example<int> e;
    Example<int*> e2;
    return 0;
}

您不必像标准库那样担心它。 例如,如果您创建了一个指针向量,则负责在让该向量超出范围之前删除它们。 然后,人们可以决定是否要删除它(也许它是临时的排序,而其他东西拥有该对象)。 他们还可以使用智能指针,以便矢量通过智能指针的析构函数销毁对象。

在这种情况下,少即是多。 您不必做任何复杂的事情。 您不必维护模板的多个版本。 最后,模板的用户拥有更多控制权...当然还有责任。

使用可按类型选择的内存释放帮助程序模板类。您无需使用模板专业化对您的类进行配音。您只能编写一个类。

#include <type_traits>
template<typename T>   // primary template
struct Releaser
{
  template<typename V>
    void release( V v ) { }
};
template<>  // explicit specialization for T = std::true_type
struct Releaser<std::true_type>
{
  template<typename V>
    void release( V v ) { delete[] v; }
};
template <class T>
class Example
{
  private:
    T data;
  public:
    Example(): data(T()) {}
    Example(T typeData): data(typeData) {}
    typedef typename std::is_pointer<T>::value_type isptr_type;
    ~Example() {
      Releaser< isptr_type >::release( data );
    }
};

但是需要知道新调用的形式,所以使用删除或删除[]。

我建议你在需要Example持有指针时T使用std::unique_ptr。如果T是一个原始指针,那么它根本不拥有它,也不应该删除它。

如果需要Example来初始化指针,请将其专用于std::unique_ptr并在默认构造函数中调用std::make_unique

template<typename T>
class Example<std::unique_ptr<T>> {
    Example() : data{std::make_unique<T>()} {}
    /* rest of the class */
};

如果你这样做,你不应该专门化你的类,T*做一个new,因为你不能初始化非拥有的指针。您应该在构造函数中接收它,如果您不希望它为 null,则可以禁用原始指针的默认构造函数。

template<typename T>
class Example<T*> {
    Example() = delete;
    Example(T* data_) : data{data_}
    /* data is not an owning pointer. No need for a destructor */
    /* rest of the class */
};

如果您遵循这些规则,则内存管理应该没有问题。