Q:

Why derived class destructor called even though base class destructor is not virtual if object is created as reference

#include <iostream>
class Database
{
public:
   Database()
   {
      std::clog << "Database object created " <<std::endl ;
   }
   ~Database()
   {
      std::clog << "Database object destroyed " << std::endl;
   }
   virtual void Open(const std::string & ) = 0 ; 
} ;

class SqlServer : public Database
{
public:
   void Open(const std::string & conn)
   {
       std::clog << "Attempting to open the connection "<< std::endl ;
   }
      
   ~SqlServer()
   {
        std::clog << "SqlServer:Database object destroyed "<< std::endl ;
   }
} ;
int main()
{
   Database &ref = SqlServer();
   ref.Open("uid=user;pwd=default");
   return 0 ;
}

output

Database object created
Attempting to open the connection
SqlServer:Database object destroyed // why this get called as destructor is not virtual in database
Database object destroyed

Note: if I replace ref by pref then everything works fine i.e. sqlserver destructor won't get called.

A:

This is a special case when const references to temporaries are involved. The destructor for the temporary is correctly invoked, rather than the destructor of the reference since, after all, the lifetime of the temporary is merely extended.

Similar to a trick that Andrei Alexandrescu uses in his scope guard. He uses a const reference to a temporary though.

According to the C++ Standard, a reference initialized with a temporary value makes that temporary value live for the lifetime of the reference itself.
the temporary variable lives as long as the reference — and when it is destroyed, the correct destructor is called.

From Generic: Change the Way You Write Exception-Safe Code — Forever

Also tackled in Why is the derived class's destructor invoked on a const reference to the base class?

A:

You're binding a temporary to a reference. Normally this is disallowed, but MSVC has an evil extension that allows it. You can reproduce this in other compilers though by declaring const Database &ref = SqlServer(); and commenting out your ref.Open() line, as temporaries may be bound by const references.
So, with your original code in MSVC, or the modified code in other compilers, the destructor messages you're seeing being logged comes from the temporary being destroyed. The reference keeps the temporary alive, and when the reference goes out of scope, so does the temporary.

