如果我有这样的类(class):
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);
析构函数的实现应该没问题,但是如果我创建一个这样的对象:
Array<int*> miArray(5);
在析构函数中,我应该删除存储在数组中的每个对象以避免内存泄漏。
我怎样才能做到这一点?
谢谢
最佳答案
你可以使用 a specialization of your destructor ,或将标记分派(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
编辑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*>
,它应该存储我的指针并让我使用它们,但绝不永远 delete
他们,因为那是试图管理生命周期。
相反,如果我想要一个 Array
管理生命周期的,我将使用相应的智能指针,使用 Array<std::unique_ptr<int>>
.这与 Array
很好地联系在一起,要求它只调用所包含对象的析构函数(它已经这样做了)。这些析构函数(即 ~unique_ptr
)将按照它们的工作传递地释放资源,一切都很好。
补充说明:
注意初始化你的
Array
的缓冲区,如果你需要 -m_pData = new T[m_nSize];
将分配默认初始化的对象。如果这些对象没有默认构造函数,它们的值将是不确定的。一个简单的解决方法是使用new T[m_nSize]{}
,它将执行值初始化——即将算术类型初始化为零,指向nullptr
的指针, 和递归的复合类型。为您的类实现复制和/或移动语义,参见 Rule of three/five/zero .就像现在一样,复制
Array
的一个实例将导致两个实例认为它们拥有相同的缓冲区,并且当它们都尝试delete
时会出现未定义的行为。delete
和delete
检查空值,所以if(m_pData != NULL)
在析构函数中是多余的。
祝你好运:)
关于c++ - 模板化类中的析构函数实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40884250/