2016-12-11 1 views
1

이 경우 question에 따르면 모든 생성자 및 소멸자가 인라인되지 않은 경우 (완전히 정의 된 유형이 필요한 경우) 스마트 포인터를 전달할 수 있습니다. 소멸자가 제공되지 않으면 컴파일러는이를 선언하고 인라인 정의를 제공하므로 스마트 포인터의 유형이 헤더에 완전히 알려 져야합니다. 기본 생성자에도 동일하게 적용됩니다.스마트 포인터 및 상속 된 생성자를 사용하여 전달 선언

그러나 상속 된 생성자에도 적용되며 나에게 다소 혼란 스럽습니다. 고려 :

class Base 
{ 
public: 
    Base(); //defined in cpp 
}; 

class SomeClass; 

class Derived : public Base 
{ 
    using Base::Base; 
    ~Derived(); //defined in cpp 

    std::unique_ptr<SomeClass> ptr; 
}; 

Derived 생성자는 명시 적으로 선언 만 소스 파일에 정의되어 있지 않으면이 컴파일되지 않습니다. 왜? Base 생성자는 인라인이 아니며 using 지시문을 사용하면 다른 멤버와 비슷한 방식으로 생성자의 "상속"이 발생해야합니다. 아니면 컴파일러는 "나를 위해 Base에서와 같은 생성자를 선언하고 인라인으로 정의"라고 해석합니까?

+0

[규칙 제로] (http://en.cppreference.com/w/cpp/language/rule_of_three)를 사용하지 않는 이유는 무엇입니까? –

+2

@ 컴파일러 컴파일러 정의 생성자/소멸자는 암시 적으로 인라인되어 헤더에 완전히 알려지기 위해 스마트 포인터에 전달 된 유형을 요구합니다 (전달 선언으로는 충분하지 않습니다). – Resurrection

+0

정말로 좋은 질문입니다. 감사! – Yola

답변

3

마지막 문장의 답입니다. 컴파일러의 해석은 using Base::Base;

로 "나는. 나를 위해를 정의하십시오했다 Base로 서명의 동일한 세트 생성자를 가지고 Derived를 원한다."

+2

그리고 기본적으로 정의를 인라인으로 만드는 다른 암시 적으로 선언 된 생성자/소멸자와 동일한 규칙을 따릅니다. 주위에 쉬운 방법이 없다고 생각합니다 (상속 된 생성자를 가졌지 만 컴파일러가 헤더에서 인라인 대신에 다른 곳을 정의하도록합니다). – Resurrection

0

Derivated의 경우 생성자를 선언하지 않았으므로 기본값 인 인라인이 생성됩니다.

기본 생성자 또는 다른 생성자가 기본 생성자를 호출한다는 사실은 인라인이 아닌 Base 생성자와 관련이없는 또 다른 항목입니다.

기본적으로 클래스의 생성자와 기본 클래스의 생성자 사이에는 연결이 없습니다. 단, 기본 클래스의 클래스가 파생 클래스의 클래스보다 먼저 실행된다는 사실은 예외입니다. 명시 적으로 말하면 기본 클래스의 기본 클래스가 호출됩니다.

+0

나는 당신이 말하는 것이 정확하다고 생각하지 않습니다. 클래스가 생성자를 상속 할 때 기본 클래스의 생성자와 명확하고 정의 된 관계가 있습니다. 해당 링크가 완전히 올바르지는 않지만 http://en.cppreference.com/w/cpp/language/using_declaration#Inheriting_constructors를 참조하십시오. 예를 들어,'struct A {A (int); }'모든 파생 클래스는 암시 적으로 기본 생성자를 선언합니다.'struct B : public A {A :: A;를 사용합니다. }'그러나 그것은 사실이 아닙니다. 생성자는 선언되었지만 암시 적으로 삭제됩니다 (VS 2015). 문제는 컴파일러가 상속 된 생성자를 정의하는 방식입니다. – Resurrection

1

우선의 코드의 작은 양으로 문제를 재현 할 수 :

#include <memory> 

class SomeClass; 

int main() 
{ 
    std::unique_ptr<SomeClass> ptr; 
} 

오류 :

In file included from /opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/memory:81:0, 
from <source>:1: 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = SomeClass]': 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:236:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = SomeClass; _Dp = std::default_delete<SomeClass>]' 
<source>:7:30: required from here 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'SomeClass' 
static_assert(sizeof(_Tp)>0, 
^ 
Compiler exited with result code 1 

같은 문제가 여기 (이 상속과 아무 상관 없다는 것을 증명하기 위해) :

#include <memory> 

class SomeClass; 

class NotDerived 
{ 
// ~NotDerived(); //defined in cpp 

    std::unique_ptr<SomeClass> ptr; 
}; 

int main(){ 
    NotDerived d; 
} 

오류 :

이제210
In file included from /opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/memory:81:0, 
from <source>:1: 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = SomeClass]': 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:236:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = SomeClass; _Dp = std::default_delete<SomeClass>]' 
<source>:5:7: required from here 
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'SomeClass' 
static_assert(sizeof(_Tp)>0, 
^ 
Compiler exited with result code 1 

의이 unique_ptr 정말 기억하자

template< 
    class T, 
    class Deleter = std::default_delete<T> 
> class unique_ptr; 

그리고 default_delete ...

Calls delete on ptr

그리고 (SomeClass에) 포인터에 deleteSomeclass을 소멸 할 것이다 그렇게 아직 신고하지 않은 SomeClass::~SomeClass

으로 전화해야합니다. 따라서 오류.

왜 관련이 있습니까?

코드에서 Derived에 대한 소멸자를 선언하지 않으면 기본적으로 ptr의 소멸자를 호출하는 기본값이 생성됩니다.

이 시점에서 컴파일러는 SomeClass이라는 완전한 정의가 필요하므로이를 파기하는 방법을 알고 있어야합니다.

Derived에서 소멸자를 선언하면이 문제가 Derived::~Derived의 imlementation으로 지연됩니다.

+0

당신은 내가 링크 한 대답은 무엇인지에 대해 설명해 주셨지만 내 질문에 대해서는 언급하지 않으 셨습니다. 왜 상속 된 생성자가 스마트 포인터 멤버에서 앞으로 선언 된 유형을 막는 지요? 컴파일러가 암시 적으로 기본 생성자 (인라인)와 같은 상속 된 생성자를 정의하므로 Martin Bonner가 제공 한 대답은 정확합니다. – Resurrection

+0

@MichaelVlach'Derived '가 파생 클래스가 아닌 경우 동일한 문제를 발견 할 수 있습니다. 상속과는 아무 관련이 없습니다. –

+0

다른 클래스를 상속하지 않으면 생성자를 상속받을 수 없으므로 동일한 문제가 발생하지 않습니다. 그 질문에 관한 내용은 제목에도 언급되어 있습니다 ... – Resurrection