2

Consider following code (minimal version):

#include <iostream>

struct Base
{
    virtual ~Base() {}

    virtual void test() const { std::cout << "base"; }
};

struct Derived : public Base
{
    void test() const { std::cout << "derived"; }
};

struct Composite
{
    const Derived &ref;

    Composite(const Derived &ref) : ref(ref) {}

    void testRef() const { ref.test(); }
};

int main()
{
    Composite c((Derived()));
    c.testRef();
}

This actually produces 'base' when using latest MinGW g++! Is that a compiler bug or am I missing something? Could someone test this in VS please?

I consider myself an experienced C++ programmer, constantly using polymorphism, stack-based references, temporary objects (C++ standard 12.2) etc. Therefore I know that lifetime lengthening should be applied.

This behaviour only occurs when defining a destructor in Base (virtual or not) and using a temporary, i. e. following usage produces 'derived':

int main()
{
    Derived d;
    Composite c(d);
    c.testRef();
}
mfontanini
  • 21,410
  • 4
  • 65
  • 73
Philip
  • 271
  • 1
  • 15
  • 2
    Could be undefined behavior, if the temp has been destroyed and yet captured (by ref) in Composite c. – Scott Jones May 02 '13 at 00:40
  • 2
    Your temporary will be destroyed before you call `c.testRef`. Your code exhibits undefined behaviour. In fact, it crashes [here](http://ideone.com/xGQilt). – mfontanini May 02 '13 at 00:42
  • @mfontanini: What about lifetime lengthening then? Why can I do `const Derived &ref = createDerived();` which returns a Derived? Like asked [here](http://stackoverflow.com/questions/4086508/const-reference-for-temporary-lifetime-lengthening). – Philip May 02 '13 at 01:08
  • 1
    @PhilipDahnen this is not lifetime lengthening. You're just storing a reference to a temporary; that temporary gets destroyed. – mfontanini May 02 '13 at 01:15
  • @mfontanini: Ok, I finally got it, thanks. Tested it again producing output in c'tor & d'tor... how can I mark your comment as the one solving my problem? – Philip May 02 '13 at 01:29
  • @PhilipDahnen you can't mark a comment as the one solving your problem. You need to pick an answer :P – mfontanini May 02 '13 at 13:00

2 Answers2

5
Composite c((Derived()));

This line creates a temporary object of type Derived, passes it to the constructor of c, and then destroys the temporary object. After that, all bets are off.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
2
Composite c((Derived()));

When you defined destructor of Base and program leave the Composite constructor , destructor of Derived and Base executed. To avoid error when calling virtual function of Base in destructor of Base(Now the Derived is destructed ), the program move the virtual function point (which is just the address of the object of this test code) from pointing virtual function table of derived to the Base. If you do not define the destructor, then do nothing . The address is still pointing to the Derived virtual function table.

 c.testRef();

The ref still get the address of the object and the address of virtual function table, and call the function in table. So the difference exists.

I test in VC 8.0 and check the memory. This happens because some kinds of "lucky".

MIKU_LINK
  • 192
  • 10