Home > Software design >  Segmentation fault when passing std::shared_ptr to subclass
Segmentation fault when passing std::shared_ptr to subclass

Time:09-22

The following code illustrates my intent: https://godbolt.org/z/dhhascnoo

#include<string>
#include<sstream>
#include<iomanip>
#include<iostream>
#include<memory>

class Dbg
{
protected:
    bool enabled;
public:
    Dbg() : enabled(false) {}
    Dbg(bool enable) : enabled(enable) {}

    void print() 
    {
        if (enabled) {
            std::cout << "Debugging!" << std::endl;
        }
    }
};

class C1
{
protected:
    std::shared_ptr<Dbg> dbg;
public:
    C1() { dbg = std::make_shared<Dbg>(false); }
    C1(std::shared_ptr<Dbg> dbg) : dbg(dbg) {}

    void print() 
    {
        dbg->print();
    }
};

class C0
{
protected:
    std::shared_ptr<Dbg> dbg;
    C1 c1Inst;
public:
    C0() : c1Inst(dbg) { dbg = std::make_shared<Dbg>(false); }
    C0(std::shared_ptr<Dbg> dbg) : dbg(dbg) {}

    void run()
    {
        c1Inst.print();
    }
};

int main()
{
    std::shared_ptr<Dbg> dbg = std::make_shared<Dbg>(true);

    C0 c0Inst;
    c0Inst.run();
}

Basically, I have some utility class that I want to pass to most of my objects that I run. With the ability to print out log messages (with configurable files to log them to).

I intend to pass a shared_ptr of this utility object to all of my subclasses. However, something about how I'm initiating the constructors to these classes seems to be off and causing a segfault.

I'm not as intimately knowledgeable about constructor design, so maybe someone can spot my mistake here?


EDIT: I realized my mistake here was not passing the actual pointer of dbg in main (doh!). It should be:

int main()
{
  std::shared_ptr<Dbg> dbg = std::make_shared<Dbg>(true);

  C0 c0Inst(dbg);
  c0Inst.run();
}

Still, the default constructor of C0 should've created a new Dbg object to reference, no?

CodePudding user response:

Your code has undefined behavior due to calling the unitized std::shared_ptr<Dbg>.

In class C0, you have not initialized the member C1 c1Inst; in its default constructor (i.e. C0():...) . Then you are calling the run() from the class

void run() {
    c1Inst.print();
}

Which will run the print from the C1 where you have not initialized again the std::shared_ptr<Dbg> dbg;. This is undefined behavior.


In order to fix, you need simply the the constrictors of the C0 be

C0()
    : dbg{ std::make_shared<Dbg>(false) }
    , c1Inst{ dbg }
{}

C0(std::shared_ptr<Dbg> dbg)
    : dbg(dbg)
    , c1Inst{ dbg }
{}

So-that all the members of the class will be initialized properly before using it. Here is a demo

CodePudding user response:

As it was said, you pass nullptr to C1, as initializer lists get called before constructor: C0(): c1Inst(dbg) {dbg=std::... so you basically not initialized pointer for C1.

To solve it, you should initialize a pointer first, so for example change default constructor to:

C0()
{
dbg = std::make_shared<Dbg>(false);
c1Inst = C1(dbg);
}
  • Related