user12700880
user12700880

Reputation: 11

static std::shared_ptr<T> member; vs std::shared_ptr<T> member;?

Right now, I think, I must make an important decision in my program. The task is the following:

I have single class base which will be inherited by multiple derived classes. Derived classes must have shared access to same instances of base members. Also, I want to access those "shared" Bases members from outside: from a 3rd class Foo, which contains all derived classes. With my current experience I came up with two solutions:

struct Base
{
  std::shared_ptr<int> m_1 = nullptr;
  std::shared_ptr<int> m_2 = nullptr;
};

struct Derived_1 : Base
{
  // using Base members and doing other stuff
};

struct Derived_2 : Base
{
  // using Base members and doing other stuff
};

struct Foo
{
  std::shared_ptr<int> m_1 = std::make_shared<int>();
  std::shared_ptr<int> m_2 = std::make_shared<int>();

  Derived_1 _d1;
  Derived_2 _d2;

  Foo()
  {
    _d1.m_1 = this->m_1;
    _d1.m_2 = this->m_2;

    _d2.m_1 = this->m_1;
    _d2.m_2 = this->m_2;
  }
};

This I have access to the same m_1 and m_2 from Foo and also from derived classes.

struct Base
{
  static std::shared_ptr<int> m_1;
  static std::shared_ptr<int> m_2;
};

// providing definitions for Base::m_1 and Base::m_2 ...

// Derived classes stay the same as in first example.

class Foo
{
  std::shared_ptr<int> m_1;
  std::shared_ptr<int> m_2;

  Foo()
  {
    this->m_1 = Base::m_1;
    this->m_2 = Base::m_2;
  }

};

In both cases I achieve same result (do I really?). Are there some advantages for one approach over the other? What are hidden drawbacks for them? What is more common approach and why? I am curious about other approaches. I am using c++17 under VS17.

Upvotes: 0

Views: 277

Answers (2)

eerorika
eerorika

Reputation: 238381

In both cases I achieve same result (do I really?).

Well, no. If you use static member, then the member is not associated with any instance, and there is exactly one shared Base::m_1 and one Base::m_2 respectively in the program. With a non-static member, every instance of Base have their own m_1 and m_2 contained within them.

Are there some advantages for one approach over the other?

One has the advantage that there is only one member in the program, and the other has the advantage that there is one member for each instance.

What is more common approach and why?

Non-static members are typically more useful. Static storage is global state, which is problematic and is discouraged.


It is unclear why Foo has the members m_1 and m2, which appear to point to the same object as members point to. Why not simply use those pointers and get rid of the pointers in Foo?

struct Foo
{
  Derived_1 _d1{std::make_shared<int>(), std::make_shared<int>()};
  Derived_2 _d2{_d1.m_1,                 _d1.m_2};
};

Sharing the bases of the derived objects is also possible which would achieve having only a single copy of the shared pointers per instance of Foo. But it is only possible if the derived instances are themselves bases of a single derived class. In such case, the sharing of the base is achieved with virtual inheritance.

struct Derived_1 : virtual Base {};
struct Derived_2 : virtual Base {};
struct Derived   : Derived_1, Derived_2 {
    Derived(std::shared_ptr<int> m_1, std::shared_ptr<int> m_2): Base{m_1, m_2} {}
};

struct Foo
{
  Derived _d{std::make_shared<int>(), std::make_shared<int>()};
};

Upvotes: 1

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122595

They are not the same. Consider this:

int main() {
    Foo f1;
    Foo f2;
    *(f1.m_1) = 5;
    *(f2.m_1) = 42;
    std::cout << *(f1.m_1);
}

For the first version without static it will output: 5, because each Foo isntance uses its own Base subobject. The second variant has some errors:

#include <memory>
#include <iostream>
struct Base
{
  static std::shared_ptr<int> m_1;
  static std::shared_ptr<int> m_2;
};

// defintions were missing
std::shared_ptr<int> Base::m_1 = std::make_shared<int>();
std::shared_ptr<int> Base::m_2 = std::make_shared<int>();

// Foo didnt inherit from Base and had a private constructor
struct Foo : Base
{
  std::shared_ptr<int> m_1;
  std::shared_ptr<int> m_2;

  Foo()
  {
    this->m_1 = Base::m_1;
    this->m_2 = Base::m_2;
  }
};

After fixing that, the above main prints 42, because there is only one Base::m_1 and only one Base::m_2.

Upvotes: 0

Related Questions