2012-06-27 5 views
42

은 다소가 직접 - 초기화를위한 두 개의 구문이, 그리고-복사 초기화 Why is copy constructor called instead of conversion constructor?복사 및 직접 초기화가 다른 동작을하는 이유는 무엇입니까? 내가 그들을 다른 정의 동작을 필요에 대한 동기를 알고 싶어</p> <pre><code>A a(b); A a = b; </code></pre> <p>:

관련. 사본 초기화의 경우 여분의 사본이 관련되어 있으며 해당 사본의 용도를 생각할 수 없습니다. 그것이 임시 직원의 복사본이기 때문에 최적화되고 최적화 될 것이므로 사용자는 자신의 일에 의존 할 수 없습니다. 추가 사본 자체가 다른 행동에 충분한 이유가되지 않습니다. 왜? 그것은 온도에서 복사 이래로

+0

편집을 진행했습니다. 내가 무엇인가를 엉망으로 만들었 으면 다시 넣어주세요 :-) –

+0

@SteveJessop : 언어 변호사라고 써야합니다. –

+8

@Als : 아마도 태그의 목적을 모르겠습니다. 질문의 아이디어는 실제로 사양이 * 말하고있는 것에 대해 미세한 털을 나누는 것이 아닙니다. 그러나 그것이 내가 언어 변호사라고 생각하는 것입니다. 그게 허용된다면 나는 언어 디자인에 태그를 달고 싶다. –

답변

3

, 및 아마는 키워드 여기 아마입니다

밖으로 최적화 될 수 있습니다. 표준을 사용하면 컴파일러가 복사를 최적화 할 수 있지만 필요하지는 않습니다. 일부 컴파일러가이 코드를 허용 (최적화 됨)했지만 다른 컴파일러가 거부 (최적화되지 않음) 한 경우 매우 일관성이 없습니다.

그래서 표준에서는이 문제를 일관된 방식으로 처리하도록 규정합니다. 모든 사람이 복사 생성자가 액세스 할 수 있는지 여부를 확인해야합니다.

모든 컴파일러는 코드를 수락하거나 거부해야합니다. 그렇지 않으면 휴대용이 아닙니다.


또 다른 예를 들어,

A a; 
B b; 

A a1 = a; 
A a2 = b; 

a2을 허용 똑같이 일치하지 않을 것이라고 생각하지만 a1A의 복사 생성자이 비공개 금지하고 있습니다.


우리는 또한 클래스 객체를 초기화하는 두 가지 방법이 다른 의도되었다는 표준 텍스트에서 볼 수

(8.5/16) :

초기화가 직접 초기화 경우, 또는 그것이 복사 - 초기화 인 경우, 소스 형의 비 정규화 된 버젼이 목적지의 클래스와 같은 클래스 또는 파생 클래스 인 경우, 생성자가 고려됩니다. 적용 가능한 생성자는 열거되고 (13.3.1.3), 과부하 해결 (13.3)을 통해 최상의 생성자가 선택됩니다. 이렇게 선택된 생성자는 이니셜 라이저 표현식 또는 표현식 목록을 인수로 사용하여 객체를 초기화하기 위해 호출됩니다. 생성자가 적용되지 않거나 과부하 해결이 모호하면 초기화가 잘못됩니다. 그렇지 않은 경우 (즉, 나머지 복사 초기화의 경우) 소스 유형에서 대상 유형으로 변환 할 수있는 사용자 정의 변환 시퀀스 또는 변환 함수 사용시 파생 클래스로 열거됩니다. 13.3.1.4에서 설명하고 가장 좋은 것은 과부하 해결 (13.3)을 통해 선택됩니다. 변환을 수행 할 수 없거나 모호한 경우 초기화가 잘못되었습니다. 선택된 함수는 이니셜 라이저 식을 인수로 사용하여 호출됩니다. 함수가 생성자 인 경우, 호출은 목적지 유형의 cv-unqualified 버전의 임시 버전을 초기화합니다. 임시는 값입니다.그런 다음 호출의 결과 (생성자의 경우 임시 임)가 위의 규칙에 따라 복사 초기화의 대상인 객체를 직접 초기화하는 데 사용됩니다. 특정의 경우, 구현은 직접 초기화되는 객체에 중간 결과를 직접 구축하여이 직접 초기화에 내재 된 복사를 제거 할 수 있습니다. 12.2, 12.8 참조.

직접 초기화는 생성 된 클래스의 생성자를 직접 사용한다는 점이 다릅니다. 카피 - 초기화 (copy-initialization)에서, 다른 변환 함수들이 고려되고, 이들은 복사되어야하는 임시를 생성 할 수있다.

+4

사실,하지만 질문에 실제로 대답하지 않습니다 ... –

+0

잠재적 인 추가 사본 **은 ** 차이의 원인입니다. :-) –

+1

미안하지만, 아직도 어떻게 보이지 않습니다. 대답에서 좀 더 설명이 가능합니까? (downvoter가 아님) –

4
만 추측

,하지만 난 정말 얼마나 확인 비얀 스트로브 스트 룹없이 더 확신하기 힘들 것입니다 두려워 : 그것은 그런 행동은 프로그래머가 예상됩니다 가정했기 때문에

그것은 이런 식으로 설계되었다 , 그는 = sign이 사용될 때 copy가 수행되고 direct initializer syntax로 수행되지 않을 것이라고 예상 할 것이다.

가능한 복사 elision은 이후 버전의 표준에만 추가되었지만 확실하지는 않습니다. 이는 표준 기록을 확인하여 누군가가 확실히 말할 수있는 것입니다. 내가 테스트 컴파일러에서

struct X 
{ 
    X(int); 
    X(const X&); 
}; 

int foo(X x){/*Do stuff*/ return 1; } 
X x(1); 
foo(x); 

foo의 인수는 항상 전체 최적화가 켜져도 함께 복사 한 :

+0

좋습니다. 그렇지만 왜 프로그래머가 * 여분의 복사본을 원했습니까? 어떤 목적에도 도움이되지 않는 것 같습니다. –

+0

동의합니다. 나에게 어떤 의미가 없지만 이것이 내가 상상할 수있는 유일한 설명이다. 나는 언어를 디자인 한 사람들 만이 그들의 이유를 말할 수있을 것이라고 생각한다. – Suma

+1

예. 또는 실제로 사본을 원했고 사용 이유를 말할 수있는 사람. –

1

는 다음을 예로 들어 보겠습니다. 이를 통해 사본을 수집 할 수 있으며 모든 상황에서을 삭제할 수 없습니다.

이제 언어 디자인 관점에서 생각해보십시오. 복사가 필요한 시점과 그렇지 않은 시점에 대한 규칙을 만들고 싶다면 생각해야 할 모든 시나리오를 상상해보십시오. 이것은 매우 어려울 것입니다. 또한 규칙을 수립 할 수 있다고하더라도 사람들이 이해하기가 매우 복잡하고 거의 불가능합니다. 그러나 동시에 모든 곳에서 사본을 강제로 작성하면 매우 비효율적입니다. 규칙이 그대로있는 이유는 사람들이 이해할 수 있도록 이해할 수있는 규칙을 만들지 만 피할 수만 있다면 사본을 만들어야하는 것은 아닙니다.

나는 지금 인정해야한다.이 대답은 Suma의 대답과 매우 흡사하다. 아이디어는 당신이 현재의 규칙으로 행동을 기대할 수 있고, 다른 것들은 사람들이 따라 가기가 너무 어려울 것이라고 생각합니다. 같은 내장 유형의

+0

foo는 값으로 인수를 취하므로 사본이 포함될 것임이 분명합니다.나는 이것이 어떤 식 으로든이 질문과 관련이 있다고 생각하지 않는다. – Tony

+0

@ 토니 : 예제의 핵심은 모든 복사본을 제거 할 수있는 것은 아니라는 것을 보여주는 것입니다. 일부 상황에서는 생략 할 수 있지만보다 일반적인 규칙을 작성한 다음 각 사용 사례에 대해 개별 규칙을 만드는 것이 더 쉽습니다. –

0

초기화 :

int i = 2; 

는 부분적으로 인해 역사적인 이유 (고등학교 수학을 기억) 매우 자연 구문입니다. 그것은보다 자연스러운 것입니다 :

int i(2); 

비록 일부 수학자들이이 점을 주장 할지라도. 결국, 함수 (이 경우에는 생성자)를 호출하고 인수를 전달할 때 부자연스럽지 않습니다.

기본 제공 유형의 경우 이러한 두 가지 유형의 초기화가 동일합니다. 전자의 경우에는 여분의 사본이 없습니다. 이것이 초기화의 두 가지 유형을 모두 갖고있는 이유이며 원래 원래대로 다르게 지정하려는 의도는 없습니다.

그러나 사용자 정의 형식이 있으며 언어의 명시된 목표 중 하나는 가능한 한 최대한 기본 제공 형식으로 작동 할 수 있도록하는 것입니다.

따라서 복사 구성 (예 : 일부 변환 함수에서 입력 가져 오기)은 첫 번째 구문을 자연스럽게 구현 한 것입니다.

추가 복사본이있을 수 있고 생략 될 수 있다는 사실은 사용자 정의 형식에 대한 최적화입니다. elion 복사와 명시 적 생성자 모두 나중에이 언어로 들어갔다. 표준이 특정 기간 후에 최적화를 허용한다는 것은 놀라운 일이 아닙니다. 또한 이제는 과부하 해결 후보에서 명시 적 생성자를 제거 할 수 있습니다.