2013-01-23 5 views
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을 열려고

생성 : 데이터베이스 객체가 파괴되었습니다 // 데이터베이스에서 가상 객체가 아닌 소멸자로 호출되는 이유

데이터베이스 객체가 파괴되었습니다.

참고 : ref로 바꾸면 pref로 처리하면 sqlserver 소멸자가 호출되지 않습니다.

+3

악의적 인 MSVC 확장으로 인해 코드가 컴파일됩니다. 일반적으로 ** 임시 **를 참조에 바인딩 할 수 없습니다. 나는 그것이 당신의 질문의 주요 초점이기 때문에 그것을 굵게했습니다. – chris

답변

5

const 임시 참조가 관련된 특수한 경우입니다. 결국 임시의 소멸자는 참조의 소멸자가 아니라 올바르게 호출됩니다. 결국 임시의 수명이 연장되기 때문입니다.


Andrei Alexandrescu가 범위 경비로 사용하는 트릭과 비슷합니다. 그는 const 임시 참조를 사용합니다.

C++ 표준에 따르면 임시 값으로 초기화 된 참조는 임시 값을 참조 자체의 수명 동안 생깁니다.

임시 변수는 참조 길이만큼 지속되며 파괴 될 때 소멸자이 호출됩니다. Generic: Change the Way You Write Exception-Safe Code — Forever


에서

또한 당신은 참조로 임시 결합하고 Why is the derived class's destructor invoked on a const reference to the base class?

3

에 달려 들었다. 일반적으로이 작업은 허용되지 않지만 MSVC는 악의적 인 확장을 허용합니다. 임시 컴파일은 const 참조에 의해 바인딩 될 수 있으므로 const Database &ref = SqlServer();을 선언하고 ref.Open() 행을 주석 처리하여 다른 컴파일러에서이를 재현 할 수 있습니다.

MSVC의 원본 코드 또는 다른 컴파일러의 수정 된 코드를 사용하면 기록중인 소멸자 메시지가 일시적으로 삭제 된 것입니다. 참조는 임시 상태를 유지하고 참조가 범위를 벗어나면 임시 상태도 유지됩니다.

0
Database &ref = SqlServer(); 

ref 임시 참조 결합, 당신은 그러나이 그것을 사용하지 않는 더 나은 const를 참조에 바인딩 VS 확장을 사용할 수 있습니다, 그 확장은 악이다. 스마트 포인터 사용을 제안하십시오.

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

참고 : 데이터베이스 클래스는 기본 클래스로 사용되지만 virtual destructor을 정의하지 않았습니다. 에 대한 포인터를 통해 파생 형식의 개체를 삭제하면 정의되지 않은 동작이 발생합니다.

관련 문제