实现对象指针的模板化双向链表

Posted

技术标签:

【中文标题】实现对象指针的模板化双向链表【英文标题】:Implementing a templated doubly linked list of pointers to objects 【发布时间】:2012-11-11 09:32:07 【问题描述】:

我对实现一个双向链表感到有点困惑,其中列表中的数据是指针。

我的链表类的私有部分如下所示:

 private:
    struct node 
      node* next;
      node* prev;
      T* o;
    ;
    node* first; // The pointer to the first node (NULL if none)
    node* last;  // The pointer to the last node (NULL if none)
    unsigned int size_;

如您所见,列表中充满了指向对象的指针,而不仅仅是普通的旧对象,这让我有点困惑。

以下是规范中的描述:

请注意,虽然此列表是跨包含类型 T 模板化的,但它只插入和删除指向 T 的指针,而不是 T 的实例。这确保 Dlist 实现知道它拥有插入的对象,它负责如果列表被复制,则复制它们,如果列表被破坏,它必须销毁它们。

这是我当前的 insertFront(T* o) 实现:

void Dlist::insertFront(T* o) 
  node* insert = new node();
  insert->o = new T(*o); 
  insert->next = first;
  insert->prev = last;
  first = insert;

这似乎是错误的。如果 T 没有复制构造函数怎么办?这如何确保列表中对象的唯一所有权?

我可以这样做吗:

insert->o = o;

这似乎不安全,因为如果你有:

Object* item = new Object();
dlist.insertFront(item);
delete item;

然后该项目也将被销毁列表。它是否正确?我的理解有问题吗?

感谢阅读。

注意:虽然这看起来像家庭作业,但事实并非如此。我实际上是一名 java 开发人员,只是通过做一个老派项目来提高我的指针技能。

【问题讨论】:

【参考方案1】:

当你有一个指针容器时,你有以下两种使用场景之一:

    给容器一个指针,容器负责在删除包含结构时删除指针。

    一个指向容器的指针,但归调用者所有。调用者负责在不再需要指针时将其删除。

上面的数字 1 非常简单。

在数字 2 的情况下,预计容器的所有者(可能也是调用者)会在删除项目之前从容器中删除项目。

我故意省略了第三个选项,这实际上是您在第一个代码示例中采用的选项。即分配一个新项目并复制它。我省略它的原因是因为调用者可以这样做。

省略它的另一个原因是您可能需要一个可以采用非指针类型的容器。通过始终使用 T* 而不是 T 来要求它是一个指针可能不像您想要的那样灵活。有时您应该将其强制为指针,但我想不出对容器执行此操作的任何用途(在我的脑海中)。

如果您允许用户声明 Dlist<MyClass*> 而不是 Dlist<MyClass>,则该列表的所有者会隐式意识到它正在使用指针,这会迫使他们从上面假设场景号 2。

无论如何,以下是您的示例和一些评论:


1. 除非有充分的理由,否则不要分配新的T 项目。这个原因可能只是封装。尽管我在上面提到你不应该这样做,但有时你可能想要这样做。如果没有复制构造函数,那么您的类可能是普通的旧数据。如果复制很重要,您应该关注Rule of Three。

void Dlist::insertFront(T* o) 
  node* insert = new node();
  insert->o = new T(*o);         //<-- Follow rule of three
  insert->next = first;
  insert->prev = last;
  first = insert;


2.这是你通常会做的事情

insert->o = o;

3. 插入后不得删除项目。将所有权传递给您的容器,或者在您和容器都不再需要该项目时删除它。

Object* item = new Object();
dlist.insertFront(item);
delete item;                     //<-- The item in the list is now invalid

【讨论】:

在 (3) 中,当您说“将所有权传递给您的容器”时,您的意思是仅设置 item = null 吗? 我的意思是不要删除它。如果您真的需要,可以将其设置为 NULL,但它只是存储在变量中的指针(即数字)。 “传递所有权”是指仅当您的容器使用所有权语义定义时: ie 它总是会在完成时删除包含的指针。在这种情况下,调用者永远不必删除或记住指针 - 容器会完成所有这些。我通常更喜欢在我的模板中提供指针类型(而不是隐式指针类型),因为容器是否拥有指针永远不会有任何混淆。 酷。谢谢,稻米,这一切都非常有帮助。 Err.. 抱歉,如果这令人困惑。允许容器拥有您的指针或自己拥有它之间没有物理区别。这是概念上的差异。您可以将指针值存储在任意数量的位置 - 但它只能被删除一次,并且在删除后永远不应该使用。

以上是关于实现对象指针的模板化双向链表的主要内容,如果未能解决你的问题,请参考以下文章

双向链表的原理与实现

静态链表循环链表双向链表

数据结构05——静态链表循环链表双向链表

大话数据结构Java程序——双向链表的实现

JavaScript 实现双向链表的操作

Java中双向链表的代码实现