2009-11-14 2 views
70

복사 생성자복사 생성자 및 C++에서 연산자 오버로드 : 일반적인 함수가 가능합니까?

이후
MyClass(const MyClass&); 

및 = 연산자 과부하

MyClass& operator = (const MyClass&); 

거의 동일한 코드, 동일한 매개 변수를 가지며 반환에서만 차이가 있지만 공통 함수를 가질 수 있습니까? 둘 다 사용하기 위해서?

+3

"... 거의 동일한 코드가 있습니다 ..."? 흠 .. 너는 틀린 일을해야만 해. 이를 위해 사용자 정의 함수를 사용할 필요성을 최소화하고 컴파일러가 모든 더러운 작업을 수행하도록하십시오. 이는 종종 자체 멤버 객체에 리소스를 캡슐화하는 것을 의미합니다. 몇 가지 코드를 보여줄 수 있습니다. 어쩌면 우리는 좋은 디자인 제안을 가지고 있을지도 모른다. – sellibitze

+1

[연산자 = 및 복사 생성자 간의 코드 중복 줄이기] 가능한 복제본 (http://stackoverflow.com/questions/1477145/reducing-code-duplication-between-operator-and-the-copy-constructor) – mpromonet

답변

96

예. 두 가지 공통된 옵션이 있습니다. 그것은 이전의 상태와 문제 자체에서 발생하는 처리에 관해서 도전을 좋은 operator=되어 제공하지만

MyClass(const MyClass& other) 
{ 
    operator=(other); 
} 

: 하나는 - - 내가 추천하지 않는 명시 적으로 복사 생성자에서 operator=를 호출하는 것입니다 할당. 또한 모든 구성원과 기지는 other에 할당 될지라도 처음부터 기본값이 초기화됩니다. 이것은 심지어 모든 회원과 기지에 유효하지 않을 수도 있으며 그것이 유효한 곳이라 할지라도 의미 상으로 중복되어 실질적으로 비쌀 수도 있습니다.

복제 생성자와 스왑 메서드를 사용하여 operator=을 구현하는 것이 점차 보편화되고 있습니다.

MyClass& operator=(const MyClass& other) 
{ 
    MyClass tmp(other); 
    swap(tmp); 
    return *this; 
} 

또는 :

MyClass& operator=(MyClass other) 
{ 
    swap(other); 
    return *this; 
} 

swap 함수가 단지 내부의 소유권을 바꿉니다 기존 상태를 정리하거나 새로운 자원을 할당 할 필요가 없기 때문에 작성하는 일반적으로 간단하다.

복사 및 스왑 이디엄의 장점은 자동으로 자체 할당 안전하고 스왑 작업이 노 쓰 로우가 아니라면 매우 예외적 인 안전하다는 것입니다.

강하게 예외적 인 경우를 제외하면 '손'으로 쓰여진 할당 연산자는 대개 배정 된 사람의 이전 자원을 할당 해제하기 전에 새 자원의 복사본을 할당해야합니다. 따라서 예외가 발생하면 새 자원을 할당 할 수 있습니다. 여전히 반환됩니다. 이 모든 것은 카피 앤 스왑 (copy-and-swap)과 함께 무료로 제공되지만 일반적으로 더 복잡하기 때문에 처음부터 오류가 발생하기 쉽습니다.

주의해야 할 점은 스왑 메서드가 실제 스왑이며 복사 생성자와 할당 연산자 자체를 사용하는 기본값 인 std::swap이 아닌지 확인하는 것입니다.

일반적으로 구성원별로 swap이 사용됩니다. std::swap이 작동하며 모든 기본 유형 및 포인터 유형에 '노 스로우'가 보장됩니다. 대부분의 스마트 포인터는 노 쓰루 (no-throw) 보장으로 바꿀 수 있습니다.

+3

실제로, 그들은 일반적인 작업이 아닙니다. 복사본 매개 변수가 처음으로 개체의 멤버를 초기화하는 동안 할당 연산자는 기존 값을 재정의합니다. 이것을 고려해 볼 때, copy ctor로부터'operator ='를 alling하는 것은 사실 아주 나쁜 것입니다. 왜냐하면 처음에 모든 값을 어떤 기본값으로 초기화하기 때문에 다른 객체의 값으로 바로 덮어 쓰기 때문입니다. – sbi

+0

나는 공통 옵션을 말했고 조작은하지 않았다. 나는 복사 생성자로부터'operator ='를 호출하는 것이 좋지 않다는 것에 완전히 동의하지만, 실제 코드가 얼마나 흔한 지 알기 위해서는 실제 코드를 합리적으로 살펴 봐야한다. –

+0

Downvoters, 설명해 주시겠습니까? –

11

복사 생성자는 원시 메모리였던 객체의 최초 초기화를 수행합니다. 대입 연산자 OTOH는 기존 값을 새로운 값으로 대체합니다. 자주 사용하지 않는 것보다 오래된 리소스 (예 : 메모리)를 해제하고 새 리소스를 할당하는 작업이 포함됩니다.

둘 사이에 유사성이있는 경우 할당 연산자가 파괴 및 복사 생성을 수행한다는 것입니다. 일부 개발자는 실제로 위치 결정 파괴 (place-in-place destruction)와 배치 복사 - 건설 (place-copy-construction)에 의한 할당을 실제로 사용했습니다. 그러나 이것은 매우 나쁜 아이디어입니다.(어떤이 경우하면 파생 클래스의 할당시라는 기본 클래스의 대입 연산자입니까?) 일반적으로 요즘 찰스으로 swap을 사용하는 표준 관용구 간주 무엇

제안 :

MyClass& operator=(MyClass other) 
{ 
    swap(other); 
    return *this; 
} 

이 복사본을 사용 -construction (참고로 other이 복사 됨) 및 파괴 (함수의 끝에서 파괴 됨) - 올바른 순서로 사용됩니다. 파괴 (파괴하지 말아야 함) 이전에 건설 (실패 할 수도 있음). 내 마음이 "복사"를 생각하고 내 상식을 자극 할 때 단어 "스왑"을 읽어,

MyClass& operator=(const MyClass& other) 
{ 
    MyClass tmp(other); 
    swap(tmp); 
    return *this; 
} 

첫째 :

+0

'swap'을'virtual'으로 선언해야합니까? – nonplus

+1

@Johannes : 가상 함수는 다형성 클래스 계층 구조에서 사용됩니다. 할당 연산자는 값 유형에 사용됩니다. 두 사람은 거의 섞이지 않습니다. – sbi

-2

뭔가에 대해 날 귀찮게. 또한, 나는이 공상 속임수의 목표에 의문을 제기한다. 예, 스왑 이전에 새로운 (복사 된) 리소스를 구성 할 때 예외가 발생해야합니다. 스왑은 모든 새 데이터가 채워지기 전에 안전하게 채워지는 것처럼 보입니다.

괜찮습니다. 그렇다면 스왑 이후 발생한 예외는 무엇입니까? (임시 객체가 범위를 벗어날 때 이전 리소스가 소멸되는 경우) 할당의 사용자 관점에서 볼 때 작업은 실패했습니다. 거대한 부작용이 있습니다. 복사가 실제로 발생했습니다. 실패한 자원 정리 만있었습니다. 외부에서 작업이 실패한 것 같아도 대상 객체의 상태가 변경되었습니다.

그래서, 내가 대신 더 자연스러운 "전송"할 "스왑"의 제안 :

MyClass& operator=(const MyClass& other) 
{ 
    MyClass tmp(other); 
    transfer(tmp); 
    return *this; 
} 

이 임시 객체의 구조가 여전히 있지만, 다음 즉각적인 조치가 모두 현재의 자원을 확보하는 것입니다 목적지는 이동하기 전에 (그리고 NULL을 두 번 해제하지 않기 때문에) 소스의 자원을 이동시킵니다.

대신에 {construct, move, destruct} 대신 {construct, destruct, move}를 제안합니다. 가장 위험한 행동 인이 조치는 다른 모든 조치가 끝난 후 마지막으로 취해진 조치입니다.

예, 두 스키마 모두에서 삭제가 실패합니다. 데이터가 손상되었거나 (생각하지 않았을 때 복사) 또는 손실되었습니다 (생각하지 않았을 때 해제 됨). 잃어버린 것이 손상된 것보다 낫습니다. 데이터가 불량 데이터보다 우수합니다.

스왑 대신 전송. 어쨌든 그것은 제 제안입니다.

+2

소멸자가 실패해서는 안되기 때문에 소멸시 예외는 예상되지 않습니다. 그리고 이동이 가장 위험한 작업 인 경우 파괴 뒤에서 이동을 움직이는 이점은 없을 것입니다. 즉, 표준 구성표에서 이동 실패는 이전 상태를 손상시키지 않지만 새 구성표는 손상되지 않습니다. 왜? 또한,'마음이 생각되면 "스왑"이라는 단어를 읽으십시오. "글쓰기"는 자극적입니다. -> 도서관 작가로서 당신은 일반적으로 일반적인 관행 (카피 + 스왑)을 알고 있고, 핵심은 '내 마음'입니다. 당신의 마음은 실제로 공용 인터페이스 뒤에 숨겨져 있습니다. 이것이 재사용 가능한 코드의 전부입니다. –