如果我有这样的课程:
Array<int> miArray(5);
如果现在我像这样创建我班级的对象:
Array<int*> miArray(5);
析构函数的实现应该没问题,但是如果我创建这样的对象:
SELECT clients.*, salesagents.name, COUNT(DISTINCT v1.id) as visits_number, COUNT( DISTINCT v2.id) as visits_number_last_month
FROM `clients`
LEFT JOIN `salesagents` ON `clients`.`salesagents_id`=`salesagents`.`id`
LEFT JOIN `visits` as `v1` ON `clients`.`id` = `v1`.`clients_id`
LEFT JOIN `visits` as `v2` ON `clients`.`id` = `v2`.`clients_id` AND `v2`.`date` > FROM_UNIXTIME(UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 MONTH)))
GROUP BY `clients`.`id`
在析构函数中,我应该删除存储在数组中的每个对象,以避免内存泄漏。
我怎样才能做到这一点?
由于
答案 0 :(得分:4)
您可以使用a specialization of your destructor或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
编辑T
添加到Array<T*>
,但是没有任何安全措施可以传递其他内容:< / p>
{
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
所有这些都是存在 No raw owning pointers 规则的原因:原始指针根本不应该管理资源生命周期。如果我使用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
检查是否为null,因此析构函数中的if(m_pData != NULL)
是多余的。
答案 1 :(得分:2)
我认为一个好的设计就是在 smart 指针类中包装原始的拥有指针(例如你的示例中的int*
),例如{{1 }或std::unique_ptr
,或其他一些RAII包装器。
这就是std::shared_ptr
基本上发生的情况,如果你想在向量中存储指向T的拥有指针,你可以拥有std::vector
或vector<unique_ptr<T>>
。
请注意,在容器中存储原始观察指针很好(只要正确处理指向对象的生命周期)。
只需补充几点注意事项:
您的班级应该禁止通过vector<shared_ptr<T>>
复制构造函数和复制分配进行复制,或者正确实现这些复制操作。因为它处于当前状态,如果人们试图复制构造或复制分配您的类的实例,则容易出错。
=delete
构造函数应标记为Array(unsigned int nSize)
,以避免来自无符号整数的隐式转换。