Nuri
Nuri

Reputation: 65

Sharing objects owned via smart pointer

Basically i have a one struct that contains objects to share between classes as following;

struct CoreComponents
{
    std::unique_ptr<a> m_A = std::make_unique<a>();
    std::unique_ptr<b> m_B;
    std::unique_ptr<c> m_C = std::make_unique<c>();
};

And in my main class i own it via unique_ptr;

class Game
{
    ...
  private:
    std::unique_ptr<CoreComponents> m_Components;
    ...
};

Then i have other n classes which i need to access that m_Components object from it's functions without creating copies. (i will not modify contents of that object)

I tried using shared_ptr to hold m_Components in Game class then pass it to other classes (to their constructors) via value and store it but that scenario causes memory leaks. (i use memcheck for checking leaks) I found out that it's the cause of the leak but i couldn't figure out why exactly.

Shared_ptr scenario

Constructor of class which i need to access CoreComponents object;

GameScene::GameScene(std::shared_ptr<CoreComponents> components)
: m_Components(std::move(components))

I'm trying to hold it as member of GameScene class then use it in functions;

std::shared_ptr<CoreComponents> m_Components;

And this is how i pass it from inside of the Game class;

auto gs = std::make_unique<GameScene>(m_Components)

General usage inside GameScene class;

m_Components->m_A->draw(*m_OtherObjectInsideGameScene);

So what is the best way to create similar design using modern c++? I was trying to avoid Singleton pattern but do i have to use it to achieve this or it's possible with better smart pointer usage?

PS: CoreComponents struct needs to be deleted from memory when Game class is destroyed.

Upvotes: 1

Views: 528

Answers (2)

xtofl
xtofl

Reputation: 41509

It seems that you correctly separate the concerns of ownership and usage. The only trouble you have is how to forward the components to the rest of your system.

I would keep your owning structure, and create dedicated structures for the specific users:

struct CoreComponents {
   unique_ptr<A> a; unique_ptr<B> b; ...
};

struct PartOfTheSystem {
  void use(A& a, B& b);
};

struct Game {
  CoreComponents components;
  PartOfTheSystem user;

  void stuff() {
    user.use(*components.a, *components.b);
  }
};

Yes: more typing.

But also: very clear logic: construction/ownership and use are separate concerns, and this is perfectly clear by design! Also refer to https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-smartptrparam.

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385174

The best way if you have shared objects is indeed to use a shared_ptr.

A unique_ptr is for unique ownership.

If you had memory leaks, it's time to investigate why that was, and fix them! Your report suggests a cyclical reference. Check for accidental lambda capture, and in some places you perhaps meant to use weak_ptr instead.

Using a singleton for this is like fixing your car's broken tyre by setting the whole thing on fire and taking a donkey instead. Your unique_ptr approach is more like fixing your car's broken tyre by removing it and driving on rims for the lols.

Upvotes: 1

Related Questions