【问题标题】: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 开发人员,只是通过做一个老派项目来提高我的指针技能。

【问题讨论】:

    标签: c++ templates pointers doubly-linked-list


    【解决方案1】:

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

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

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

    上面的数字 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.. 抱歉,如果这令人困惑。允许容器拥有您的指针或自己拥有它之间没有物理区别。这是概念上的差异。您可以将指针值存储在任意数量的位置 - 但它只能被删除一次,并且在删除后永远不应该使用。
    猜你喜欢
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2013-11-15
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多