# 取得自己的 shared pointer

## 目標

在 class 的 member function 裡面取得自己的 shared\_ptr 或（weak\_ptr）。

Example: 把底下的 code 轉成用智慧指標來管理記憶體的版本

```cpp
struct Node;
struct Node {
    Node() = default;
    ~Node() = default;
    
    void setLeft(Node* l) {
        // assume node has no parent
        left = l;
        left->parent = this;
    }
    
    void setRight(Node* r) {
        right = r;
        right->parent = this;
    }

    Node* parent;
    Node* left;
    Node* right;
};
```

### 錯誤嘗試?

很遺憾，`std::make_shared<Node>(this)` 是完全行不通的，他會製造出一個新的 shared\_ptr ，也就是說用同一個物件會被 destruct 一次以上。

[https://godbolt.org/z/a56q8ajqc](https://godbolt.org/z/a56q8ajqc)

```cpp
#include <memory>
#include <iostream>

struct Foo {
    Foo() = default;
    ~Foo() {
        std::cout << "~Foo()" << std::endl;
    }

    auto get() {
        return std::shared_ptr<Foo>(this);
    }
};

int main() {
    auto a = std::make_shared<Foo>();
    auto b = a->get();

    return 0;
}
```

Result:

```plaintext
Program returned: 139
double free or corruption (out)
Program terminated with signal: SIGSEGV
~Foo()
```

## `std::enable_shared_from_this`

[https://en.cppreference.com/w/cpp/memory/enable\_shared\_from\_this](https://en.cppreference.com/w/cpp/memory/enable_shared_from_this)

用法在文件寫得很清楚了：

1. 讓 class 繼承 std::enable\_shared\_from\_this
    
2. 使用 shared\_from\_this 或 weak\_from\_this (C++17)
    

### 實作

> A common implementation for enable\_shared\_from\_this is to hold a weak reference (such as std::weak\_ptr) to \*this. For the purpose of exposition, the weak reference is called weak-this and considered as a mutable std::weak\_ptr member.
> 
> The constructors of std::shared\_ptr detect the presence of an unambiguous and accessible (i.e. public inheritance is mandatory) enable\_shared\_from\_this base and assign the newly created std::shared\_ptr to weak-this if not already owned by a live std::shared\_ptr.

也就是說，std::shared\_ptr 在建構時，會檢查 instance 是不是繼承自 enable\_shared\_from\_this ，是的話就把自己塞到 enable\_shared\_from\_this 內部的 weak\_ptr 。

### 問題：假如 instance 不是 shared\_ptr 形式會怎麼樣？

[https://godbolt.org/z/jjfsh49MW](https://godbolt.org/z/jjfsh49MW)

```cpp
#include <memory>

struct Foo : public std::enable_shared_from_this<Foo> {
    auto get() {
        return shared_from_this();
    }
};

int main() {
    Foo a;
    auto b = a.get();
    return 0;
}
```

結果噴出：

```plaintext
Program returned: 139
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
Program terminated with signal: SIGSEGV
```

從實作上就可以得知，因為 enable\_shared\_from\_this 內部存的 weak\_ptr 裡面是空的，然後在 shared\_from\_this 時嘗試將它轉成 shared\_ptr，所以失敗。

所以需要避免使用者直接建立一個 instance 例如：把 constructor 設為 private，並且提供一個 static function 負責 create shared\_ptr。

## Code?

```cpp
#include <memory>
#include <iostream>

class Node;
using NodePtr = std::shared_ptr<Node>;
using WeakNodePtr = std::weak_ptr<Node>;

class Node : public std::enable_shared_from_this<Node> {
public:
    static NodePtr create() {
        return NodePtr(new Node());
    };

    ~Node() {
        std::cout << "~Node()" << std::endl;
    }

    NodePtr getParent() const {
        return parent_.lock();
    }

    void setLeft(NodePtr node) {
        // assume node has no parent
        left_ = node;
        left_->parent_ = weak_from_this();
    }

    void setRight(NodePtr node) {
        right_ = node;
        right_->parent_ = weak_from_this();
    }

private:
    Node() = default;

    WeakNodePtr parent_;
    NodePtr left_;
    NodePtr right_;
};

int main() {
    auto root = Node::create();
    auto node1 = Node::create();
    auto node2 = Node::create();
    root->setLeft(node1);
    root->setRight(node2);
    return 0;
}
```
