c++shared-ptrundefined-behaviorobject-lifetimevptr

Unexpected virtual function dispatch when using base class reference instead of pointer


Let say I have a simple class hierarchy as follows with a common api:

#include <memory>

class Base {
    public:
        void api() {
            foo();
        }

    protected:
        virtual void foo() {
            std::cout << "Base" << std::endl;

        }
    };

    class FirstLevel : public Base {
    protected:
        virtual void foo() {
            std::cout << "FirstLevel" << std::endl;
        }
    };

when I use the base class pointer I get the correct dispatch as follow:

std::shared_ptr<Base> b = std::make_shared<Base>();
std::shared_ptr<Base> fl = std::make_shared<FirstLevel>();

b->api();
fl->api();

Which correctly prints :

Base
FirstLevel

However when I use the base class reference the behavior is unexpected:

Base &b_ref = *std::make_shared<Base>();
Base &fl_ref = *std::make_shared<FirstLevel>();

b_ref.api();
fl_ref.api();

which prints:

FirstLevel
FirstLevel

Why is the dispatch different when using references as opposed to pointers?


Solution

  • You have undefined behaviour, because the references are dangling at the point you use them to call api(). The objects managed by the shared pointers cease to exist after the lines used to initialize b_ref and fl_ref.

    You can fix it by having references to objects that are still alive:

    auto b = std::make_shared<Base>();
    auto fl = std::make_shared<FirstLevel>();
    
    Base &b_ref = *b;
    Base &fl_ref = *fl;