模板类中的破坏者实现
destructor implementation in templated 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);
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
时,不确定的行为。delete
和delete
检查null的检查,因此destructor中的if(m_pData != NULL)
是多余的。
祝你好运:)
我认为,一个好的设计就是在 smart pointer类中仅包装RAW 拥有 pointer Pointer(例如int*
),例如std::unique_ptr
或std::shared_ptr
,或其他一些RAII包装器。这是std::vector
基本上发生的事情,如果要将拥有的指针存储到向量中,则可以使用vector<unique_ptr<T>>
或vector<shared_ptr<T>>
。
请注意,在容器中存储RAW 观察的指针很好(就尖头物体的寿命而言,要适当照顾)。
只是其他注释:
-
您的班级应通过
=delete
复制构造函数和复制分配禁止副本,或者正确实施这些副本操作。就像当前状态一样,如果人们尝试复制类的构造或分配您的班级实例。 -
Array(unsigned int nSize)
构造函数应标记为explicit
,以避免隐式从无签名的ints转换。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在类实现中为字符串的覆盖默认破坏者
- 模板类中的破坏者实现