我有一个看起来像这样的泛型类:
template <class T>
class Example
{
private:
T data;
public:
Example(): data(T())
Example(T typeData): data(typeData)
~Example()
// ...
};
我对如何为这样的事情实现解构器感到有些困惑。具体来说,由于T
是任何类型,它可能是在堆栈上分配的内存(通过无参数构造函数创建的Example
总是如此)或在堆上。
例如,如果客户端将T
的类型设为int*
并提供指向动态内存的指针,我如何知道在delete
上调用data
为如果客户端将类型设置为int
?
答案 0 :(得分:7)
最简单的答案是:不要。不要试图猜测用户并做一些他们可能没想到的事情。采用与标准容器相同的策略:假设T
正确清理。
如果客户端代码编写正确,它将使用RAII类(如智能指针)自动和正确管理内存和其他资源。如果不是,您不能希望在提供商代码中修复它。
让您的课程与std::unique_ptr
和std::shared_ptr
一起使用,以及任何其他自定义RAII课程,并让您的客户自己进行管理。毕竟,如果他们想要存储非拥有指针怎么办?
答案 1 :(得分:2)
您可以使用模板专业化。
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;
}
答案 2 :(得分:0)
您可以不像标准库那样担心它。例如,如果创建指针向量,则在让向量超出范围之前,您负责删除它们。然后人们可以决定他们是否甚至想要删除它(也许它是临时的排序和其他东西拥有对象)。他们也可以使用智能指针,这样vector就可以通过智能指针的析构函数来破坏对象。
在这种情况下,少即是多。你不必做任何复杂的事情。您不必维护模板的多个版本。最后,模板的用户当然还有更多的控制权和责任感。
答案 3 :(得分:0)
当您需要std::unique_ptr
来持有拥有指针时,我建议您将T
用于Example
。如果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 */
};
如果遵循这些规则,您应该对内存管理没有任何问题。
答案 4 :(得分:0)
使用可按类型选择的内存释放帮助程序模板类。 您不需要使用Template Specialization对您的课程进行加分。 你只能写一个班级。
const
但需要知道新调用的形式,所以使用删除或删除[]。