Home > Mobile >  How to use a shared_ptr from interface implementation
How to use a shared_ptr from interface implementation

Time:09-25

Let’s say that DoSomething method is the implementation of an interface. I can’t change its signature. How could DoSomething instantiate MyClass2 with the second constructor and provide a smart pointer to the current instance of MyClass (not a copy) ?

#include <Windows.h>
#include <iostream>


class MyClass;

class MyClass2 {
public:
  std::shared_ptr<MyClass> ptr;

  MyClass2() {
    ptr = nullptr;
  }

  MyClass2(std::shared_ptr<MyClass> ptrParam) {
    ptr = std::move(ptrParam);
  }

};

class MyClass {
public:
  int value;

  MyClass() :
    value{1} {
    OutputDebugString(L"MyClass\r\n");
  }

  ~MyClass() {
    OutputDebugString(L"~MyClass\r\n");
  }

  std::shared_ptr<MyClass2> DoSomething() {
    return std::make_shared<MyClass2>();
  }

};

int main() {
  auto ptr = std::make_shared<MyClass>();
  auto ptr2 = ptr->DoSomething();
}

CodePudding user response:

The only way for this to work is if DoSomething has access to a smart pointer pointing to the instance of MyClass. You can't place a shared_ptr in MyClass because that would create a reference loop, creating a memory leak.

However, there is another type of smart pointer: weak_ptr. It was designed for pretty much this purpose: when you need a smart pointer, but you don't want to create a reference loop.

class MyClass {
public:
  int value;
  std::weak_ptr<MyClass> selfReference;

  MyClass() :
    value{1} {
    OutputDebugString(L"MyClass\r\n");
  }

  ~MyClass() {
    OutputDebugString(L"~MyClass\r\n");
  }

  void giveSelfReference(std::shared_ptr<MyClass>& sr) {
    selfReference = sr;
  }

  std::shared_ptr<MyClass2> DoSomething() {
    return std::make_shared<MyClass2>(selfReference.lock());
  }

};

So, then main would look like:

int main() {
  auto ptr = std::make_shared<MyClass>();
  ptr->giveSelfReference(ptr);
  auto ptr2 = ptr->DoSomething();
}

Edit: There is a comment recommending std::enable_shared_from_this<T>::shared_from_this, I'm not familiar with this, but it looks to be a somewhat more elegant version of my solution.

  • Related