1
#include <iostream>

class A
{
    public:
        virtual ~A() = default;
        virtual void foo(void) = 0;
};

class B : public A
{
    private:
        int x;

    public:
        B(int a) : x(a) {}
        void foo(void) { std::cout << "B: " << x << "\n"; }
};

class Foo
{
    private:
        A* a_ptr;

    public:
        Foo (B& x) { a_ptr = &x; }
        A* get_ptr(void) { return a_ptr; }
        void dummy(void) { std::cout << "Foo: "; std::cout << a_ptr << "\t "<< typeid(*a_ptr).name() << "\n"; a_ptr->foo(); std::cout << "\n"; }
};

int main(void)
{
        B b(10);
        Foo f(b);

        f.dummy();
        return 0;
}

If the constructor of Foo takes a reference to an object of B, then this program executes the way I expect it to, i.e. a_ptr->foo() calls B::foo().

However, if the constructor is changed to accept the parameter by value, then a_ptr->foo() resolves to A::foo(), and results in a pure virtual method called exception

Sample output (Passed by reference:):

Foo: 0x7fffe90a24e0      1B
B: 10

Sample output (Passed by value):

Foo: 0x7fffc6bbab20      1A
pure virtual method called
terminate called without an active exception
Aborted (core dumped)

I've a vague hunch as to why this might be happening, and I'm looking for some literature or reference which might prove or disprove my hypothesis: When passed by reference, the base class pointer a_ptr points to an entity whose lifetime exceeds past the call to a_ptr->foo().

However, when passed by value, a_ptr points to a temporary which is lost when the constructor exits.

I suppose this has something to do with the VTABLE of A, but I can't quite put my finger on it.

8
  • 2
    Object slicing? Commented Aug 6, 2020 at 20:53
  • I might have close this wrong. Did you change Foo (B& x) { a_ptr = &x; } to Foo (B x) { a_ptr = &x; }? Commented Aug 6, 2020 at 20:56
  • 2
    I don't think this is object slicing, its a pointer to a temporary Commented Aug 6, 2020 at 20:58
  • Please post a minimal reproducible example. So far you’ve only posted code which doesn’t exhibit the problem you’re describing. Commented Aug 6, 2020 at 21:02
  • 2
    Show the code that doesn’t work, not the code that works. Commented Aug 6, 2020 at 21:02

2 Answers 2

5

Yes, your suspicion is correct.

When the B object is passed by value into the Foo constructor, it becomes a local variable of the constructor. The constructor is saving a pointer to that local object, which goes out of scope when the constructor exits.

So, the call to a_ptr->foo() in Foo::dummy() is actually undefined behavior since a_ptr doesn't even point at a valid object to begin with. But, it doesn't really crash since A::foo() doesn't use its this pointer for anything. It just points to a compiler-defined function that throws the pure virtual method called error, which you don't catch, so your program terminates.

Sign up to request clarification or add additional context in comments.

Comments

2

You assigned temporary object B by reference to a_ptr which is of type A*. On constructor exit this temporary object has beed destroyed. As VTABLE has been destroyed too, called A::foo, which is pure virtual. So you got it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.