2016-11-17 11 views
2

다음 코드가 제대로 비주얼 스튜디오 2013와 함께 컴파일 :기본 이동 생성자가 unique_ptr에 사용 된 클래스의 default-deleter를 필요로하는 이유는 무엇입니까?

#include <memory> 

namespace NS 
    { 
    class SomeOtherClass; 

    class MyClass 
     { 
     public: 
     MyClass(); 
     virtual ~MyClass(); 
     private: 
     std::unique_ptr<SomeOtherClass> m_someOtherClass; 
     }; 
    } 

int main() 
    { 
    auto mc = NS::MyClass(); 
    } 

이 때문에 main에서 mc의 초기화가 직접 이동 생성자 확인하지 않고 최적화 된 비주얼 스튜디오 2013의 버그입니다.

이동 생성자가 존재해야하기 때문에 비주얼 스튜디오 2015에서이 컴파일되지 않습니다, 그래서 우리는이에 코드를 변경합니다

#include <memory> 

namespace NS 
    { 
    class SomeOtherClass; 

    class MyClass 
     { 
     public: 
     MyClass(); 
     virtual ~MyClass(); 
     MyClass(MyClass&&) = default; 
     private: 
     std::unique_ptr<SomeOtherClass> m_someOtherClass; 
     }; 
    } 

int main() 
    { 
    auto mc = NS::MyClass(); 
    } 

을 그리고 다시 컴파일.

하지만 이제 DLL을 내보내려는 경우 컴파일이 다시 실패합니다. 기본 생성 입주 생성자 SomeOtherClass을 파괴 할 수있는 필요로

memory(1193): error C2027: use of undefined type 'NS::SomeOtherClass' 
test.cpp(5): note: see declaration of 'NS::SomeOtherClass' 
... 
memory(1194): error C2338: can't delete an incomplete type 
memory(1195): warning C4150: deletion of pointer to incomplete type 'NS::SomeOtherClass'; no destructor called 

것 같다 :

#include <memory> 

namespace NS 
    { 
    class SomeOtherClass; 

    class __declspec(dllexport) MyClass 
     { 
     public: 
     MyClass(); 
     virtual ~MyClass(); 
     MyClass(MyClass&&) = default; 
     private: 
     std::unique_ptr<SomeOtherClass> m_someOtherClass; 
     }; 
    } 

int main() 
    { 
    auto mc = NS::MyClass(); 
    } 

이 컴파일러 출력의 일부입니다 :이 수정 된 코드입니다. MyClass에는 완전 정의가 SomeOtherClass 인 소멸자가 있기 때문에 이상합니다.

그럼 왜이 DLL을 내보낼 때 컴파일되지 않습니까? 기본 이동 생성자가 SomeOtherClass의 정의를 알아야하는 이유는 무엇입니까?

+0

왜 그런지는 말할 수 없습니다 (좋은 질문입니다). 당신은 당신이'MyClass :: MyClass (MyClass &&) = default; '를 여러분의 cpp 파일에 가지고 있고 헤더 파일에있는 선언 만 가지고있을 때 이것을 고칠 수있다. – Hayt

+2

'main()'에'NS :: MyClass mc;'를 쓸 수 없습니까? – alain

답변

2

std::unique_ptr에는 삭제를 처리하기위한 완전한 유형이 필요합니다.

귀하의 채무 불이행 이동 생성자는 인라인 다음과 같은 의사에 의해 표현 될 수있다 :

MyClass(MyClass&& other): 
    m_someOtherClass(std::move(other.m_someOtherClass)); 
{} 

이 완전한 형태로 SomeOtherClass을 필요로 그것을 템플릿 기본 Deleter가 이동할 수 있도록. dllexport

와 인라인 C++ 함수를 정의에

MSDN 당신은 인라인 dllexport 속성을 가진 함수를 정의 할 수 있습니다. 이 경우 함수는 항상 인지 여부에 상관없이 함수에서 인스턴스화되고 내보내집니다. 함수 은 다른 프로그램에서 가져온 것으로 가정합니다.

내가 VS2015 편리,하지만하지 않습니다 단지 클래스의 생성자를 선언하고 SomeOtherClass 트릭해야 정의 된 변환 단위에서 정의 :

class __declspec(dllexport) MyClass 
     { 
     public: 
     MyClass(); 
     virtual ~MyClass(); 
     MyClass(MyClass&&); 
     private: 
     std::unique_ptr<SomeOtherClass> m_someOtherClass; 
     }; 
    } 

file_containing_ ~ 인 MyClass.cpp를

MyClass::MyClass(MyClass&&)=default; 
+0

대답하기 전에, 나는 SomeOtherClass가 파괴 될 필요가 없다는 가정하에있었습니다. 그러나 당신이 지적한대로, 그것은 그렇습니다. unique_ptr의 릴리스 후에는 'other'인스턴스에 nullptr이 포함되며 nullptr을 삭제해도 소멸자가 필요하지는 않지만 unique_ptr의 소멸자 구현에는 여전히 소멸자를 호출하는 코드가 포함됩니다. 따라서이 경우에는 절대 호출되지 않지만 필요할 수 있습니다. – Patrick

+0

@pat 아니, 그게 아니야, 이동 소스를 파괴하지 않습니다 그냥 nulls. – Yakk

+0

@krz 아니요, 허용 된 이동 생성자가 아닙니다. MyClass (MyClass && other) : m_someOtherClass (std :: move (other.m_someOtherClass)) {}'이어야합니다. 그리고 심지어 이동 - ctor에서, 이동 ctor 필요가 없습니다'.reset', 그래서 나는 그것이 허용되지 않습니다 믿습니다 ... – Yakk