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 ;
}

出力

データベース オブジェクトが作成されました

接続を開こうとしています

SqlServer:Database object destroy // デストラクタとして呼び出されるこれがデータベースで仮想でない理由

データベース オブジェクトが破壊されました

注: ref を pref に置き換えると、すべて正常に動作します。つまり、sqlserver デストラクタは呼び出されません。

4

3 に答える 3

5

これは、const一時オブジェクトへの参照が含まれる特殊なケースです。参照のデストラクタではなく、テンポラリのデストラクタが正しく呼び出されます。結局のところ、テンポラリの有効期間は単に延長されるだけだからです。


Andrei Alexandrescu がスコープ ガードで使用するトリックに似ています。彼はconst一時的なものへの参照を使用しています。

C++ 標準によると、一時的な値で初期化された参照は、その一時的な値を参照自体の有効期間にわたって有効にします。

一時変数は参照が存在する限り存続し、破棄されると正しいデストラクタが呼び出されます。

ジェネリックから: 例外セーフ コードの記述方法を変更する — 永久に


また、基底クラスへの const 参照で派生クラスのデストラクタが呼び出されるのはなぜですか。

于 2013-01-23T02:47:35.333 に答える
3

一時的なものを参照にバインドしています。通常、これは許可されていませんが、MSVCにはそれを許可する邪悪な拡張機能があります。一時的なものはconst参照にバインドされる可能性があるため、行を宣言const Database &ref = SqlServer();してコメントアウトすることで、他のコンパイラでこれを再現できます。ref.Open()

したがって、MSVCの元のコード、または他のコンパイラの変更されたコードでは、ログに記録されているデストラクタメッセージは、一時的に破棄されたものです。参照は一時的なものを存続させ、参照がスコープ外になると、一時的なものも存続します。

于 2013-01-23T02:47:56.070 に答える
0
Database &ref = SqlServer();

refVS拡張を使用してconst参照にバインドできますが、それを使用しない方が良いです。これらの拡張は悪です。スマート ポインターの使用を提案します。

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");

注: Database クラスは基本クラスとして機能しますが、定義されていませんvirtual destructor。ベースへのポインターを介して派生型のオブジェクトを削除すると、未定義の動作が発生します。

于 2013-01-23T03:47:29.787 に答える