2017-12-31 217 views
2

암시 적으로 정의되고 명시 적으로 선언 된 기본/복사 생성자의 차이점은 무엇입니까? 명시 적으로, 또한암시 적으로 정의 된 대 명시 적으로 선언 된 생성자

road::road(){} 

road::road(const road & c_road):id(c_road.id)), type(c_road.type)), 
    nodes(c_road.nodes){} 

내 질문처럼 내 자신의 생성자를 정의의 차이는 무엇인가 암시

struct road{ 
std::string id; 
std::string type; 
std::vector<int> nodes; 
road(road && m_road); 
}; 

을 정의

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
    road() = default; 
    road(const & road c_road) = default; 
    road(road && m_road); 
    }; 

를 선언 I 명시 적으로 기본 생성자를 선언해야합니까 (= default; version) 아니면 암시적인 것에 의존해야합니까? 어떤 버전이 더 빠르고 안전합니까? 어떤 버전이 잘못 되었습니까?

답변

1

"규칙 제로"를 살펴볼 수 있습니다. 클래스가 이미 복사/이동 생성자가 정의 된 멤버 와이즈 복사본을 수행하기 때문에 클래스는 생성자가 필요하지 않습니다. 더 복잡한 유형의 리소스를 다루거나 거래해야한다면 다른 이야기 일 것입니다. 이상적으로, 당신의 클래스는 다음과 같이 표시됩니다

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
}; 

당신이 복사 생성자를 사용자가 선언하지만, 이동 생성자를 생략하면, 컴파일러는 하지 당신을위한 이동 생성자를 생성합니다. 그래서 세 가지가 모두 필요합니다. 마찬가지로 할당 연산자를 구현하려는 경우 복사 할당/이동 할당이 필요합니다. 이것은 각각 3/5의 규칙으로 알려져 있습니다. 간단하게 유지하고 필요한 것을 정의하십시오.

+0

하나 추가 할 것이라고 생각 : 복사 (또는 이동)되지 생성자를 추가 할 ** 복사기 (및 이동) 생성자를 생성하지 못하도록 **되지 않습니다 **. – Zereges

+0

또한 .. 컴파일러가 원치 않는 ctors 또는 할당을 생성하지 못하게하려면 "... = delete;"를 사용하십시오. 선언. 예 : "T (const T &) = delete;" 복사 또는 "T & operator = (const T &&) = delete;"를 허용하지 않습니다. 이동 할당을 금지합니다. –

0

명시 적으로 기본값 (인라인) 대 암시 적으로 기본값 : 여기에는 거의 차이가 없습니다. 그것은 주로 문체의 선택입니다. 개인적으로, 작은 클래스 (< 1 스크린)의 경우, 어디에도 정의되어 있지 않다는 것을 쉽게 알 수 있으므로 걱정하지 않아도되며, 클래스에 길이가 더해집니다.

더 길고 중요한 클래스의 경우 명확해야합니다. 이렇게하면 값 의미 (최소 이동 가능) 또는 ID 의미 (부동 성) 여부, 복사 가능 여부, 불확실성 여부 (할당 불가능한 경우) 등 사용자에게 즉시 알립니다.

하나의 실제 차이점은 특수 멤버 중 일부를 선언하면 다른 멤버가 암시 적으로 생성되지 않는다는 것입니다. 가장 일반적인 예는 복사 생성자/할당을 직접 구현해야하는 경우입니다. 이렇게하면 이동 생성자/할당의 자동 생성이 비활성화됩니다. 따라서 기본값을 명시 적으로 지정해야합니다 (기본값을 원할 경우).

다른 많은 중요한 차이점은 다음과 같습니다. 클래스가 .h와 .cpp 파일로 분할되는 경우 (대부분의 비 템플릿 클래스가 있어야 함),이 두 가지 접근 방식 모두에서 모든 코드가 생성됩니다. 머리글. 이렇게하면 컴파일이 느려집니다. 그래서 세 번째 방법은이 작업을 수행하는 것입니다

// .h file 
struct Foo { 
    Foo(const Foo&); // declare, but not define 
}; 

// .cpp 
Foo::Foo(const Foo&) = default; 

이 여전히 발생하는 회원을 활용하지만, 당신이 그것을 원하는 .CPP 코드를 유지합니다. 따라서 크고 템플릿이 아닌 클래스의 경우 일반적으로 =delete을 사용하거나 물건을 선언하지만 =default은 선언하지 않거나 암시 적으로 생성하도록합니다!

자신의 스페셜 멤버를 정의하는 한 : 스페셜 멤버를 직접 정의해서는 안됩니다. 그리고 기본값을 작동하도록 노력해야합니다. 생성자 자체를 정의 할 때는 일반적으로 각 멤버를 한 번 언급해야합니다.회원을 추가하거나 제거하면 조용히 잊어 버릴 수있는 것을 포함하여 유지 보수 작업이 진행됩니다. 0의 규칙 : http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/을 참조하십시오.

특별한 경우 : 기본 생성자. 다른 생성자가 있으면 암시 적으로 생성되지 않습니다. 그런 다음 다시 되돌리려면 =default과 똑같이 쉽게 보이고 간단히 정의하면됩니다. 이들은 동일하지 않습니다. 특히 후자는 여전히 사용자 정의 생성자로 계산되며 이는 예를 들어 클래스가 trivially_constructible으로 간주되지 않으므로 trivial이 아니므로 pod이되지는 않습니다. 이는 일부 어플리케이션에서 중요 할 수 있습니다.

+0

고맙습니다. 귀하의 링크가 특히 도움이되었다, 내 C + +를 지식이 지금 더 완벽하다고 생각합니다. 다른 사용자가 아마도 당신보다 더 많은 담당자를 필요로하기 때문에 나는 당신의 대답을 받아들이지 않았습니다. 값/신원 의미에 대해 조금 자세히 설명해 주시겠습니까? – Konstantinoscs

+0

@ Constantinoscs 글쎄요, 가치 의미론은 정수와 같습니다. 주위를 복사 할 수 있으며, 정수의 값에 따라 등가가 결정됩니다. 다형성 클래스는 특히 값 의미를 가질 수 없습니다. 당신이 기본 포인터로 무언가를 잡았을 때 그것을 복사 할 수 없을 수도 있고, 종종 크고 복잡하기 때문에 단순한 가치 기반 평등 비교가 쉽지 않습니다. 그래서 당신은 그러한 클래스를 카피 불가능하게 만들고, 정체성을 통해 동등성을 제공 할 수 있습니다 (정확히 동일한 객체 인 경우). 그것은 큰 주제입니다. 아마도 google을 원할 것입니다 :-). –