2015-01-15 5 views
2

복사 생성자가 호출되지 않고 이유가 확실하지 않습니다. 여기 내 코드 :템플릿 클래스 복사 생성자가 호출되지 않았습니다.

template <typename T> 
class SmartPtr 
{ 
    public: 
     explicit SmartPtr(T *p) : m_p(p) { cout << "ctor" << endl; } 
     SmartPtr(const SmartPtr& p) : m_p(p.m_p) { cout << "copy ctor" << endl;} 

    private: 
     T* m_p; 
}; 

int main() 
{ 
    SmartPtr<int> pt4 = SmartPtr<int>(new int); 
} 

출력은 "ctor"입니다. 기본 복사 생성자가 사용 된 것 같습니다. "명시 적"을 추가하면 오류가 발생하여 컴파일되지 않습니다.

"error: no matching function for call to ‘SmartPtr<int>::SmartPtr(SmartPtr<int>)’" 

여기서 내가 뭘 잘못하고 있니?

+5

. "copy elision"으로 검색하십시오. – juanchopanza

+0

[가능한 경우 복사 생성자가 호출되지 않는 이유는 무엇입니까?] (http://stackoverflow.com/questions/1758142/why-copy-constructor-is-not-called-in-thiscase) – stefaanv

+0

@stefaanv 처음 여기 나는 받아 들여진 대답이 실제로 틀린 것을 보았습니다 ... – Barry

답변

1

이것은 Copy Elision으로 알려져 있습니다. 사본이 명확하게 필요하지 않은 좋은 최적화입니다. 대신에 효과적으로 코드 실행 :

SmartPtr<int> __tmp(new int); 
SmartPtr<int> ptr4(__tmp); 
__tmp.~SmartPtr<int>(); 

컴파일러 따라서 __tmpptr4을 구성하기 위해 존재한다는 것을 알고 있습니다 것은 원래 ptr4 마치 실제 코드가 소유 한 메모리에 현재 위치에서 __tmp를 구성 할 수있다 실행은 다음과 같습니다.

컴파일러에게이 작업을 수행하지 말라고 지시 할 수 있습니다. 이제, 코드 인쇄를 예를 들어, GCC에, 당신은 -fno-elide-constructors 옵션을 전달할 수 있으며, 그 하나의 변화 (추가 소멸자를 기록) :

ctor 
copy ctor // not elided! 
dtor  
dtor  // extra SmartPtr! 

demo를 참조하십시오. 표준에서

, §12.8 : 복사가 생략되고

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • In a return statement in a function with a class return type, when ...
  • In a throw-expression, when ...
  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
  • when the exception-declaration of an exception handler (Clause 15) ...

[Example:

class Thing { 
public: 
    Thing(); 
    ~Thing(); 
    Thing(const Thing&); 
}; 

Thing f() { 
    Thing t; 
    return t; 
} 

Thing t2 = f(); 

Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing : the copying of the local automatic object t into the temporary object for the return value of function f() and the copying of that temporary object into object t2 . Effectively, the construction of the local object t can be viewed as directly initializing the global object t2 , and that object’s destruction will occur at program exit. Adding a move constructor to Thing has the same effect, but it is the move construction from the temporary object to t2 that is elided. —end example ]

+0

고마워요. "명시 적"작업을 추가하지 않는 이유는 무엇입니까? 컴파일러가 복사 생성자를 인스턴스화하는 것을 방해하지 않는 것처럼 보입니다. –

+0

@SyedH 복사 생성자가 코드에서 암시 적으로 호출되기 때문입니다. 명시 적으로 호출하고 싶다면'SmartPtr pt4 (SmartPtr (new int)); ' – Barry

+0

선언과 동시에 복사 생성자를 사용한다고 생각했습니다. 어떤 경우에, 왜 그 행은 암시 적으로 변환됩니까? 그것은 무엇으로부터 전환되고 있습니까? 두 유형 모두 동일하게 보입니다. 어쨌든 코드를 변경 한 것처럼 컴파일러가 여전히 같은 방식으로 불평합니다. 'SmartPtr :: SmartPtr (SmartPtr )'에 대한 호출에 일치하는 함수가 없습니다. ' –