2
#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.

Community
  • 1
  • 1
Suri
  • 3,287
  • 9
  • 45
  • 75
  • 3
    That code only compiles because of an evil MSVC extension. You can't normally bind a **temporary** to a reference. I bolded that because it's the key focus of your question. – chris Jan 23 '13 at 02:45

3 Answers3

5

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?

Community
  • 1
  • 1
Karthik T
  • 31,456
  • 5
  • 68
  • 87
3

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.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
0
Database &ref = SqlServer();

ref binds to a temporary reference, you could use VS extension to bind to a const reference however that's better is not use it, those extensions are evil. Suggest use smart pointer.

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 ; 
   virtual ~Database() {}
} ;


std::unique_ptr<Database> conn(new SqlServer());
conn->Open("uid=user;pwd=default");

Note: your Database class serves as a base class but hasn't defined virtual destructor. You get undefined behavior if you delete an object of a derived type through a pointer to the base.

billz
  • 44,644
  • 9
  • 83
  • 100