我已经编程了大约8个月,所以我对编程很陌生,并且遇到了ADT,包括Doubly Linked List。
我意识到我看到的双重链接列表实现都没有在免费商店中,它们都在堆栈上。不会让免费存储上的每个节点都具有更高的内存效率,考虑到如果从列表中删除特定节点,您可以立即在所述节点上调用delete,而不是等待整个LinkedList结构超出范围?
至少如果我理解正确,只需使用正常的重新链接过程从列表中删除节点,实际上不会释放节点占用的内存。
我知道免费商店与新关键字相关联,如果有新商品,则应遵循删除。我了解到,您实际上不应该使用原始指针来管理内存,因为如果您忘记删除免费商店中的项目,则会出现内存泄漏。幸运的是, C ++ 11引入了智能指针可以解决这个问题,但问题是,究竟谁是免费商店中链接列表结构中节点的所有者?
在一个非常基本的LinkedList中,我们可能有这个
struct Node
{
int _value;
Node * _next = nullptr;
Node * _prev = nullptr;
Node(int value) : _value(value) {}
};
class LinkedList
{
Node * _head = nullptr;
Node * _tail = nullptr;
int _count = 0;
public:
//ctors & dtor
//getters & setters & other methods
};
其中 _count 是当前存储在链接列表中的元素数。考虑到不应该使用原始指针来管理内存,我想到了,我应该将一些原始指针转移到C ++ 11中引入的 库中的智能指针。
问题是, 1)我真的没看到,谁应该拥有在免费商店中创建的节点,即。我应该将哪些原始指针转换为智能指针?
2)另一个问题是, std :: unique_ptr 对于此实现是否足够?即使我使用 std :: unique_ptr ,一旦我从列表中取消链接,是否会删除一个节点?程序将如何知道,节点不再使用?
非常感谢您的回复。
编辑:作为参考,我正在添加两个方法,构造函数和我的实现的Insert方法。这就是我在堆栈上有一个LinkedList的意思。正如您所看到的,我没有在我的代码中的任何地方使用新的,但是,链接列表可以工作。
LinkedList(int value)
{
Node newNode(value);
_head = &newNode;
_tail = &newNode;
_count++;
}
void InsertAtEnd(int value)
{
Node newNode(value);
//tail points to nothing, list is empty
if (_tail == nullptr)
{
_head = &newNode;
_tail = &newNode;
_count++;
}
//list is not empty
else
{
_tail->_next = &newNode;
_tail = &newNode;
_count++;
}
}
答案 0 :(得分:1)
考虑实现一个智能指针:如果你盲目地遵循规则,你需要一个智能指针来实现一个智能指针。在这种情况下,您有一个例外。类似地,对于链接列表,节点之间的指针不代表所有权。相反,列表(class LinkedList
)拥有所有节点,而在内部它们只是连接"。
为了所有这些的完整性并实施" A"在" ADT"中,需要隐藏这些实现细节。特别是,用户永远不应该直接访问节点。这也意味着列表和节点形成一个单元(通常存在C ++ friend
关系),并且在内部它们使用原始指针(就像智能指针一样)。由于这是受到外部保护的,因此不使用原始指针的规则的例外是合理的。
注意:
std::list
,请不要认真考虑使用它。std::deque<Node>
成员来存储节点。在该容器内,您甚至可以维护已使用和未使用的元素的列表。是的,它有点作弊,但它使所有权管理安全(即没有内存泄漏),同时仍然为您提供构建链表的学习体验。