2013-09-06 3 views
5

이 코드를 테스트하고 있는데 이것이 컴파일 타임에 실패하지 않은 이유가 궁금하십니까? 저는 C++ 11과 g ++ 4.7.2를 사용하고 있습니다.C++ 생성자의 이상한 동작

필자의 프로덕션 코드에서 비슷한 구조를 가졌으므로 런타임에 오류가 발생했다가 잘못된 인수 유형으로 클래스를 생성하고있는 것으로 나타났습니다. 당신이 Work 생성자에 Word를 통과 할 수 있도록

#include <iostream> 
#include <vector> 


typedef std::vector<std::string> Word; 

class Data { 
    public: 
     const Word &word; 
     Data(Word w) : word(w) {} 
}; 

class Base{ 
    const Data &data; 
    public: 
     Base(const Data &d): data(d) {} 
     ~Base() {} 
}; 

class Work : public Base{ 
    public: 
     Work(const Data &d): Base(d){} 
     ~Work() {} 
}; 


int main(int argc, char **argv){ 
    Word words; 
    words.push_back("work"); 

    /* 
    * I'm confused with this constructor, why this passed the compilation 
    * ?? 
    * Any special rule to reason this scenario ?? 
    * 
    * But obviously it will fail at run time. 
    */ 
    const Work *work = new Work(words); 

    return 0; 
} 
+1

암시 적 변환이 어딘가에서 진행되고 있을까요? –

+0

단어가 Data 생성자에 의해 Data로 변환 된 다음 Work (Data)를 호출합니다. – ZijingWu

+0

왜 실패해야합니까? http://ideone.com/cxkf4X에서 성공을 반환합니다. – xanatos

답변

10

DataWord에서 작도입니다. 내부적으로 Data 인스턴스가 전달 된 Word에서 만들어지고 생성자에 전달됩니다.

당신은 다음과 같이 explicitWord 소요 Data의 생성자 표시하여이 문제를 피할 수 있습니다 다음 Work 생성자에

class Data { 
    public: 
     const Word &word; 
     explicit Data(Word w) : word(w) {} 
}; 

그 방법은, 생성자는 암시 적으로, 더 이상 적용 할 수 있으며 사용자의 전화를 것이다 공동 작업이

const Work *work = new Work(words);  // Implicit call, fails to compile. 
const Work *work = new Work(Data(words)); // Explicit call, compiles. 
+1

물론 'Data'의 생성자는 인수에 대한 참조를 바인딩하기 때문에 작동하지 않습니다.이 생성자는 생성자가 반환 할 때 소멸됩니다. –

+1

@MM. 예, 맞습니다. '단어'는'main()'에 국한되어있어'Work'의 인스턴스가'main()'에 대해서도 지역적이기 때문에 중요하지 않지만'Work' 생성자는 임시'Data' 인스턴스를 James 그게 나쁜 소식이에요. –

+1

이제는 내 프로그램이 실행 시간 동안 segfault를 제공하는 이유를 이해했습니다 (매달려있는 참조에 액세스 할 때 충돌 함). –

5

: 당신이 명시 적으로 Data 생성자를 호출하지 않는 한 컴파일 실패 mpiles *DataWord 참조한다 암시 적 변환 생성자가 있기 때문에 :

Data(Word w) : word(w) {} 

이것은 당신이 그런

Word words; 
Data d1 = words; 
Data d2(words); 

으로 일을 할 수 있다는 것을 의미하고 생성자를 통해 Data에서 Work를 구성 할 수 있습니다 Work(const Data &d): Base(d){} :

Work w(d2); 
이 동작 explicit로 변환 생성자를 선언함으로써 억제 할 수
Work w2(words); // constructs Data temporary from words, then constructs w2 with it 

:

explicit Data(Word w) : word(w) {} 

을 * 사용자 아무튼 단지 하나의 사용자 - 정의 된 변환을 포함하기 때문에 다음과 같은 의미도 유효 임시 Data 개체에 대한 매달려있는 참조가 포함되어 실제로 작동하지 않습니다.

+0

질문 옆에'Data' 클래스에 매달려있는 참조 때문에 정의되지 않은 동작이 아닌가? '단어'는 임시 객체를 참조합니다. – deepmax

+0

@MM. 그냥 그것에 대한 메모를 추가했습니다 :) – juanchopanza

2

다음 생성자가 종료되면 데이터

class Data { 
    public: 
     const Word &word; 
     Data(Word w) : word(w) {} 
}; 

자동 저장 기간의 변수 w를 유지하도록 생성된다 : 참조 형의 부재 word 더 이상 존재하지 않는 객체를 참조한다. 해당 변수에 대한 참조를 멤버 word으로 저장하면 생성자 종료시에 심판이 삭제됩니다.

다른 문제와 관계없이, 나는 이것이 귀하의 의도라고 생각하지 않습니다.