1

I'm trying to implement the linked list by indirect pointer, which introduced on the TED Talk.

I refer to felipec's implementation on github and made an version by raw pointer, this is the github link.

This is part of the full code, _find is a function that can find the indirect pointer of target node, which means *indirect == target node :

//...
struct Node {
    int data;
    Node *next;
    Node()
        : data(0), next(nullptr) {}
    Node(int _d, Node *_next = nullptr)
        : data(_d), next(_next) {}
    ~Node() { puts("~Node"); }
};
//...

List::Node **List::_find(const int target)
{
    Node **indirect = &head;
    while (*indirect && (*indirect)->data != target)
        indirect = &(*indirect)->next;

    return indirect;
}

I wanna make a smart pointer version of this. I use std::unique_ptr for the next pointer in Node, and std::shared_ptr for the head pointer in List.

But in the part Node **indirect = &head, I have no idea for how to design it by smart pointer, I have wrote this:

//...
struct Node {
    int data;
    std::unique_ptr<Node> next;
    Node()
        : data(0), next(nullptr) {}
    Node(int _d, std::unique_ptr<Node> &_next)
        : data(_d), next(std::move(_next)) {}
    ~Node() { puts("~Node"); }
};
//...

List::Node **List::_find(const int target)
{
    Node **indirect = &(head.get());
    while (*indirect && (*indirect)->data != target)
        indirect = &(*indirect)->next;

    return indirect;
}

Apparently, Node **indirect = &(head.get()) is not an good idea since the get function return a rvalue that it point to. But what I need is the pointer object that point to the target, the code even can't be compiled.

Thus, there is two question

  1. How could I get the address of the target object in smart pointer?

  2. Did I use the smart pointer in correct way? Should I change shared_ptr to unique_ptr, or just not use smart pointer for it?

Any additional supplements and recommendations are appreciated.

Mes
  • 177
  • 7

1 Answers1

1

How could I get the address of the target object in smart pointer?

I think you mean "the address of the pointer in the smart pointer", because the address of the target object is just what you get with .get(). std::unique_ptr does not offer any interface to access it's pointer member directly, so it is impossible.

Did I use the smart pointer in correct way? Should I change shared_ptr to unique_ptr, or just not use smart pointer for it?

Using std::unique_ptr is the correct thing to do. You don't need shared_ptr because there are never two owners of any given node.

In your first code indirect is a pointer to a raw pointer in the Node/List structure. Since you changed these to smart pointers, indirect should also become a pointer to a smart pointer:

std::unique_ptr<List::Node> *List::_find(const int target)
{
    std::unique_ptr<Node> *indirect = &head;
    while (*indirect && (*indirect)->data != target)
        indirect = &(*indirect)->next;

    return indirect;
}

Although it would be more idiomatic to return a reference instead:

std::unique_ptr<List::Node> &List::_find(const int target)
{
    std::unique_ptr<Node> *indirect = &head;
    while (*indirect && (*indirect)->data != target)
        indirect = &(*indirect)->next;

    return *indirect;
}

(I am assuming that this is a private helper function and not actually the interface of the List class, in which case there would be problems with either implementation.)

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Thank for your answer :) Does this kind of design break some rule of using `unique_ptr` ? Or it's fine since it didn't take the ownership? – Mes Dec 27 '21 at 04:47
  • @Mes It doesn't break any rules that wouldn't be broken by the raw pointer version as well. The important thing is that the returned pointer is only valid until you remove the node containing the pointed-to pointer and if you add/remove element in the list, the node that the returned pointer points to after two indirections may change. – user17732522 Dec 27 '21 at 09:10