模板类中的破坏者实现

destructor implementation in templated class

本文关键字:破坏者 实现      更新时间:2023-10-16

如果我有这样的类:

template <class T>                            
class Array {                                              
 private:                                        
  T *m_pData;                                   
  unsigned int m_nSize;                         
 public:                                         
 Array(unsigned int nSize) : m_nSize(nSize),m_pData(nullptr) {                                           
 if(m_nSize > 0)
  m_pData = new T[m_nSize];                
 }                                           
 ~Array() {                    
  if(m_pData != NULL) {
   delete [] m_pData;
  }
};

如果现在我创建了这样的班级对象:

Array<int> miArray(5);

destructor的实现应该是可以的,但是如果我创建这样的对象:

Array<int*> miArray(5);

在破坏者中,我应该删除存储在数组中的每个对象,以避免内存泄漏。

我该如何实现?

谢谢

您可以使用destuructor的专业化,也可以将tag-dispatch用于删除函数(这将更加灵活)。但是,这导致了非常尴尬和脆弱的设计。假设您已经实现了相当于push_back的等效物,请考虑以下这些用户代码段:

{
    Array<int*> arr;
    arr.push_back(new int(42)); // new is on the side of the user
} // ... but delete is not. Weird.

这也导致了整个错误:您只将new ED T S提供给Array<T*>,但是没有任何安全性,可以防止其他事物传递:

{
    Array<int*> arr;
    int i = 42;
    arr.push_back(&i); // No diagnostic
    arr.push_back(new int[17]); // No diagnostic either
} // Undefined behaviour from calling `delete` on stuff that hasn't been `new`ed

所有这些都是存在没有原始的指针规则的原因:原始指针根本不应管理资源寿命。如果我使用 Array<int*>,它应该存储我的指针并让我使用它们,但永远不要 ever delete它们,因为那是试图管理终生。

相反,如果我想要管理生命周期的Array,我将使用Array<std::unique_ptr<int>>使用相应的智能指针。这与Array很好地联系在一起,要求它仅调用所包含对象的攻击函数(已经做到)。这些破坏者(即~unique_ptr)将像他们的工作一样透明地处理资源,一切都很好。

其他注释:

  • 如果需要,请注意初始化Array的缓冲区 - m_pData = new T[m_nSize];将分配默认的initialialized对象。如果这些对象没有默认构造函数,则它们的值将不确定。一个简单的解决方法是使用new T[m_nSize]{},它将执行价值限制化 - 也就是说,将算术类型初始化为零,指向nullptr和复合类型。

  • 实现您的班级的副本和/或移动语义,请参见三/五/零的规则。如今,复制Array实例将导致两个实例认为它们拥有相同的缓冲区,并且当两者都尝试delete时,不确定的行为。

  • deletedelete检查null的检查,因此destructor中的if(m_pData != NULL)是多余的。

祝你好运:)

我认为,一个好的设计就是在 smart pointer类中仅包装RAW 拥有 pointer Pointer(例如int*),例如std::unique_ptrstd::shared_ptr,或其他一些RAII包装器。这是std::vector基本上发生的事情,如果要将拥有的指针存储到向量中,则可以使用vector<unique_ptr<T>>vector<shared_ptr<T>>

请注意,在容器中存储RAW 观察的指针很好(就尖头物体的寿命而言,要适当照顾)。


只是其他注释:

  1. 您的班级应通过=delete复制构造函数和复制分配禁止副本,或者正确实施这些副本操作。就像当前状态一样,如果人们尝试复制类的构造或分配您的班级实例。

  2. Array(unsigned int nSize)构造函数应标记为 explicit,以避免隐式从无签名的ints转换。