1

i tried to make this:

#include <iostream>
#include <memory>

class B
{
    public:
    std::string var;
    
    B()
    {
        var = "original";
    }

    void print()
    {  
        std::cout << "composition " << std::endl;
    }
};

class A
{
    public:
    int a_attribute = 10;
    std::unique_ptr<B> b;

};

int main()
{
    A a;
    a.b->print();
}

That seems to work fine, except when i try to access the attributes of B, with e.g:

std::string test = a.b->var;

which leads to segmentation fault error

why i'm not getting an error to a.b->print(); but getting segfault to a.b->var; ?

Guinther Kovalski
  • 1,629
  • 1
  • 7
  • 15
  • 3
    Where do you think the pointer `a.b` points? Note that you haven't asked a question - we are forced to guess what you are asking here. – Drew Dormann Feb 22 '22 at 17:32
  • 3
    After `A a;` add `a.b = std::make_unique();` and *voilà!* – Eljay Feb 22 '22 at 17:33
  • any tips on why i need to make this? i would accept this as an answer if you choose to. – Guinther Kovalski Feb 22 '22 at 17:35
  • 2
    Because `A` has a smart pointer member variable that is being default initialized to `nullptr`. Dereferencing a `nullptr` is **undefined behavior**, which can include anything, such as segmentation fault. – Eljay Feb 22 '22 at 17:37
  • 1
    this is not caused by typos , and is reproducible. Vote to reopen. Just becuase its obvious to some doesnt mean its not a good queston – pm100 Feb 22 '22 at 17:55
  • 1
    you need to set b pointing at something `a.b = std::make_unique();` – pm100 Feb 22 '22 at 17:56
  • 1
    @DrewDormann to be fair, if he had used naked pointer a) it would still have failed B) we would have said 'use unique_ptr' – pm100 Feb 22 '22 at 17:57
  • 1
    @pm100 that's very fair. I don't suspect a naked pointer would have worked any better. With the added question, this seems to be asking why UB exists or what UB looks like or why some errors are not caught at compile-time. – Drew Dormann Feb 22 '22 at 18:02
  • Thank you @pm100, i was about to say my question is not caused by typos, and is reproducible, but i don't have enough reputation to vote for reopen – Guinther Kovalski Feb 22 '22 at 18:07
  • 1
    @GuintherKovalski With your added question, I think this question will be reopened soon. Hopefully someone will direct you to _why_ Undefined Behavior can be unpredictable regarding `a.b->print();` or `a.b->var;`. (Both are Undefined Behavior) – Drew Dormann Feb 22 '22 at 18:11
  • 1
    Related reading (perhaps duplicates): [Is segfault guaranteed when dereferencing null pointer (C/C++)](https://stackoverflow.com/questions/46104370/is-segfault-guaranteed-when-dereferencing-null-pointer-c-c) and [Segmentation Fault does not happen when try to use NULL pointer in C++](https://stackoverflow.com/questions/22137717/segmentation-fault-does-not-happen-when-try-to-use-null-pointer-in-c) and possibly the closest match [Why no segfault on member function call?](https://stackoverflow.com/questions/19409362/why-no-segfault-on-method-lookup/) – Drew Dormann Feb 22 '22 at 18:39

1 Answers1

2

You problem is here, in A you have

std::unique_ptr<B> b;

this creates a smart pointer to a B object. But it there is no B object that it points at. Before you can use it you must create a B object and set 'b' to point at it.

I dont know exactly how and when you want to create your B but you can do this

A a;
a.b = std::make_unique<B>();
a.b->print();

this will create a new B using the default contructor and make 'a.b' point at it. This is more effiecient short hand for

A a;
B *b1 = new B;
a.b.reset(b1);
a.b->print();

which explicitly creates a B and then sets a.b to point at it.

Note that you do not have to free the B object. Thats the point of smart pointers they will do it for you.

You asked why some combinations work and some dont.

You had Undefined Behavior. This can do anyting , including worst of all, appearing to work. Then at midnight on Christmas eve your largest customer submits a huge order to your system and it crashes. Every professional dev has had some occurrence of this. Ways to avoid: crank up the compiler warning levels, never ignore warnings. Use a tool like valgrind or other commercial checker tools.

For me your original code as posted worked. Why, because the invoked method doesnt actually need any data in the B object. But If I change to this

void print()
{
    std::cout << "composition " << std::endl;
    std::cout << var << std::endl;
}

it fails because now we are referencing data in the B object, but there isn't one.

Note that on a different compiler your original code will not work

pm100
  • 48,078
  • 23
  • 82
  • 145
  • i tried to put this in the A constructor: A() { this->b = std::make_unique(); } it will lead to any problem with nullptr reference too? – Guinther Kovalski Feb 22 '22 at 19:50
  • 1
    @GuintherKovalski no that will work fine. If it doesnt work edit the question to show *exactly* what you did – pm100 Feb 22 '22 at 19:57