我的代码中有几个问题。第一个是在变量"Element"中,它对我来说很好,只要发送模板的类的构造函数的变量有默认值,有没有办法跳过构造函数而不在类中放入默认值?另一个问题是,当谈到释放内存时,当T是指针类型时,我需要进行删除,但就在我放入代码时,我遇到了一个错误,有其他解决方案可以帮助我吗?我会注意你的答案,谢谢:D
namespace Linked{
template <class T>
struct Nodo{
const bool isponter = is_pointer<T>::value;
T Element;
Nodo<T> *Next;
Nodo(){
this->Next = nullptr;
}
~Nodo(){
if(is_pointer<T>::value)
delete Element;
}
};
}
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next = nullptr;
~Nodo(){
if constexpr (std::is_pointer<T>::value)
delete Element;
}
};
您还应该考虑T是否是指向数组的指针。
您的代码唯一的语法问题是,您没有#include <type_traits>
,忘记了is_pointer<T>::value
之前的std::
。
但你试图做的事情会带来所有权方面的问题。当Nodo
包含一个指针时,它不应该拥有该指针所指向的对象。所以你不能只delete
那个指针,因为你甚至不知道它指向哪里。考虑以下三种情况,每种情况都需要不同的处理,但你无法确定你面临的是什么情况:
Nodo<int*> n1, n2, n3;
n1.Element = new int(1); // requires delete
n2.Element = new int[10]; // requires delete[], crashes with delete
int i = 0;
n3.Element = &i; // no delete at all, crashes with delete
通常,无论谁在堆上分配了一个对象,都要负责释放它。Nodo
不应该试图释放它没有分配的内存。
由于您没有指定c++版本,我假设您使用最新的版本,现在是c++17。最适合您现有代码的是使用if constexpr
,我不会详细说明,因为还有其他很好的答案。如果您被困在C++14或C++11上(或者更糟的是,03/98,在这种情况下您应该简单地升级(,您将需要专门化您的模板。(我会回到这里(
然而,这段代码违反了CppCoreGuidelines:ES.24: Use a unique_ptr<T> to hold pointers
。通过编写模板来检测原始指针并删除它,总是必须进行分配。因此,您的链接列表不能引用现有内容的某些子数据。正如评论中所回避的那样,如果用户希望清理内存,请使用std::unique_ptr
。一个例子:
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
}
// Has ownership
auto node = Nodo<std::unique_ptr<int>>{};
node.element = std::make_unique<int>(42);
// Has ownership (to array of 42 elements)
auto node = Nodo<std::unique_ptr<int[]>>{};
node.element = std::make_unique<int[]>(42);
// No ownership
int value = 42;
auto node = Nodo<int>{};
node.element = &value;
有了这一点,所有权对来电者来说是明确的,对你来说是透明的。(因为您不需要了解数组,std::unique_ptr知道这一点(您可能需要对t进行一些限制,比如添加static_assert(std::is_nothrow_move_constructable<T>);
。
上述解决方案解决了C++11及以上版本中的问题,应该是推荐的方法。
如果没有,如果您的条件在C++17中的专用类中不可捕获,请使用if constexpr
。以及C++14和C++11中的部分专业化。
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*>{
T *Element{nullptr};
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() { delete Element; }
};
}
如果你不想重复你的代码太多
namespace Linked{
template <class T, class Me>
struct AbstractNodo{
T Element;
Me *Next{nullptr};
// All common code
};
template <class T>
struct Nodo : AbstractNodo<T, Nodo<T>>{
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*> : AbstractNodo<T, Nodo<T*>>{
Nodo() = default;
~Nodo() { delete Element; }
};
}
还有一种方法可以专门化单个方法,但是,我不太熟悉它,请参阅Stack overflow:模板化类中单个方法的模板专门化以了解更多详细信息。