2015-01-06 4 views
5

나는 아래의 18 행에있는 코드가 "복사해야 할 멤버 중 하나가 참조 일 때 암시 적으로 정의 된 대입 연산자를 사용하는 것이 좋지 않기 때문에"형식이 잘못되었다고 말했습니다.왜 클래스 멤버가 참조 인 경우 개체를 복사하는 것은 불법입니까?

나는 그것을 이해할 수 없었다. 참조를 복사 할 수없는 이유는 무엇입니까? 16 번 라인이 합법적 인 이유는 무엇입니까? 16 번 줄은 18 번 줄과 매우 유사합니다. 복사 생성자가 여전히 복사를해야합니다.

1 #include <iostream> 
2 
3 struct A 
4 { 
5 A(int& var) : r(var) {} 
6 
7 int &r; 
8 }; 
9 
10 int main(int argc, char** argv) 
11 { 
12 int x = 23; 
13 
14 A a1(x); 
15 
16 A a2 = a1; 
17 
18 a2 = a1; 
19 
20 return 0; 
21 } 
+2

[전체 퀴즈를 게시 하시겠습니까?] (http://stackoverflow.com/questions/27792560/c-why-constructor-aa-a-is-illegal) – WhozCraig

+0

아 .. 그 말이 맞습니다. 97.4 % 테스트 btw에 grat. – WhozCraig

+1

* copy *가 아니라 * assign *에 불법입니다. – Potatoswatter

답변

1

C++에서 참조를 다시 할당하는 것은 불법이므로. 당신이 (컴파일러에 의해 생성) 대입 연산자를 사용하는 경우

int &a = some_int; 
a = some_other_int; // value copied not reference 
a = some_int; // value copied not reference 

, 그것은 맹목적으로 객체의 복사본을 수행하고 따라서 귀하의 참조를 다시 할당하려고 따라서 유효하지 않습니다.

a2 = a1;라고 말하면 컴파일러는 a1.r에서 a2.r으로 재 지정하려고 시도합니다. 컴파일시 컴파일에 실패합니다.

참조는 automatically dereferenced constant pointer으로 생각할 수 있습니다. 따라서 라인 a2 = a1;은 아래 클래스와 같은 이유로 잘못된 형식으로 유지됩니다.

struct A 
{ 
    A(int *var) : p(var) {} 
    int * const p; 
}; 
+3

참조를 리 바인드하는 것은 불법입니다. 거기에 대한 구문조차 없습니다. 그러나 불법이라고 표시 한 진술은 그렇지 않습니다. –

+0

잘못된 주석을 삭제했지만 'a1.r = a2.r'이 부적절하지 않으므로 추론은 여전히 ​​잘못되었습니다. 두 번째 참조를 첫 번째 참조의 참조 대상에 간단하게 바인딩하기 때문에 다른 참조에서 하나의 참조가 초기화되지 않는다. –

+0

참조는 영구적으로 참조 해제 된 포인터와 같습니다. – seand

6

라인 16은 복사 생성자를 사용하고, 라인 18은 할당 연산자 operator=을 사용합니다. 서로 다른 두 가지 기능이 있습니다.

참조를 리바운드 할 수 없으므로 컴파일러에서 암시 적으로 할당 연산자를 생성 할 수 없습니다. 따라서이 작업을 거부하고 오류가 발생합니다.

복사 생성자가 처음으로 개체를 생성하므로 자신의 생성자에서와 같은 방법으로 해당 참조를 바인딩 할 수 있습니다.

3

참조 멤버가있는 클래스에는 기본적으로 제공되는 복사/이동 할당 연산자가 없습니다. 바인딩이 설정되면 참조를 리바운드하여 다른 변수를 참조 할 수 없습니다. 즉, 복사 생성자가 초기 설정을 수행하는 반면 기본 할당 연산자는 변경 후 후 바인딩을 시도합니다.

따라서이 표준은 기본 복사 및 이동 할당 연산자에 대해이 사례를 호출합니다.

C++ 11 § 12.8p23 삭제 된 X가 있으면 클래스 X에 대한 부도 복사/이동 할당 연산자가 정의

:

  • A의 변형 부재 중요하지 않은 상응하는 대입 연산자이고 X는 유니온 유사 클래스이거나
  • const 비 클래스 유형 (또는 그 배열)의 비 정적 데이터 멤버이거나
  • 참조 유형의 비 정적 데이터 멤버 또는
  • 오버로드 해결 (13. 1) 때문에 복사/이동할 수없는 클래스 유형 M (또는 그 배열)의 비 정적 데이터 멤버.3)은 M의 해당 대입 연산자에 적용되면 모호하거나 기본 할당 지정 연산자에서 삭제되거나 액세스 할 수없는 함수가되거나
  • 직접 또는 가상 기본 클래스 B는 오버로드 해결 (13.3)은 B의 해당 대입 연산자에 적용되면 모호하거나 기본 할당 대입 연산자에서 액세스 할 수없는 함수가되거나
  • 이 아닌 대입 연산자, 비 정적 데이터 멤버 또는 직접 기본 클래스의 경우 이동 할당 연산자가 없으며 쉽게 복사 할 수없는 유형이거나 직접 또는 간접 가상 기본 클래스입니다.

자신의 오버로드를 작성할 수 있습니다.

#include <iostream> 

struct A 
{ 
    A(int& var) : r(var) {} 

    int &r; 

    A& operator=(const A& obj) 
    { 
     r = obj.r; // value copied, reference-binding remains the same 
     return *this; 
    } 
}; 

int main(int argc, char** argv) 
{ 

    int x = 42; 
    int y = 43; 

    A a1(x); 
    A a2(y); 

    A a3 = a1; // legal. default copy-ctor invoked 
    a3 = a2; // legal. user-defined copy-assignment invoked 

    std::cout << x << ',' << y << '\n'; 

    return 0; 
} 

출력

43,43 

그러나 이것은하지 않을 것이다 (그리고 수 없습니다) 참조를 바인딩. 여기서 제공되는 오버로드는 데이터로 변경합니다. 참조 자체는 아닙니다. 이러한 구분은 중요합니다.

희망이 도움이됩니다.