2017-02-08 6 views
0

나는 단순히 개체에 대한 참조를 전달하거나 C++에서 해당 개체의 전체 복사본을 만드는 대신 개체의 얕은 복사본을 실제로 만드는 것이 궁금한가요?C++에서 참조 대신 얕은 복사본을 사용하는 이유는 무엇입니까?

내 이해는 읽기 전용 또는 변경 불가능한 개체가있는 경우 단순히 참조를 사용하려는 것입니다. 원본을 변경하지 않고 복사본을 변경해야하거나 일부 데이터를 다른 메모리 주소 공간에 마샬링하는 경우 깊은 복사본을 만듭니다.

개체에 쓰고 딥 복사본을 완성하기 전에 쓰기 복사본에 얕은 복사본을 사용하고 있지만 얕은 복사본을 사용하려는 다른 이유가 있습니까?

편집 : 질문을 명확하게하려고합니다. (C++ 11 가정)

+0

예를 들어, T & around, 참조 (또는 가능한 포인터)를 루트 객체에 전달하는 것에 대해 이야기하고 있습니다. – vijay267

답변

2

여기 테이블의 두 가지 옵션은 :

  1. 얕은 복사 생성자/할당 연산자를 가진 개체.

  2. 비싸거나 복사 할 수없는 개체입니다. C++ 11에서는 얕은 이동 생성자/할당 연산자를 사용합니다.

C++은 궁극적으로 가치 지향 언어입니다. 이처럼 간단 C++ 17 일까지 :

T t = someFuncReturningT(); 

적어도 이론적으로 복사/이동 작업을 자극한다. C++ 17의 보장 된 elision은 이것이 일어나지 않는다는 것을 확인하지만 그때까지는 T으로 복사/이동하는 것으로 간주됩니다. 물론, 거의 모든 컴파일러가 그것을 생략 할 것입니다. 그러나 그것은 이론적으로 여전히 존재합니다.

그러나 이동 작업을 수행 할 때 얕은 사본이 없어도 그렇게 나쁜 것은 아닙니다.

비싼 복사 + 얕은 이동을 원할 이유는 복사가 단순한 "복사"가 아닌 유형에 대한 것입니다. 예 : shared_ptr. 복사는 포인터 또는 두 개를 복사하는 것이 아닙니다. 당신은 또한 참조 카운트를 충돌합니다. 실제로 이것은 shared_ptr을 유형으로 디자인 한 결과입니다. 객체에 대해 여러 소유자를 허용하는 것입니다.

그럴 수있는 유일한 방법은 각 소유자가 자신의 복사본을 가지고있는 경우입니다. 따라서 복사는 그 점에서 "얕게"이루어져야합니다.

개체 디자인의 일부인 경우 이점이 있습니다.


이전 C++ 11 일에 대해 이야기하는 경우 얕은 사본이 더 적합합니다. 포스트 -C++ 11, 당신은 저렴한 이동 작업에 의존 할 수 있지만 프리 C++ 11은 사용할 수 없습니다. 따라서 얕은 복사는 값으로 객체를 합리적으로 반환하는 유일한 방법입니다.

+2

이 글은 OP가 "읽기 전용이거나 변경 불가능한 객체를 가지고 있다면, 단순히 참조를 사용하기를 원할 것입니다"라고 어떻게 해석할까요? –

+0

@barakmanos : 무엇에 대한 참고 사항? 벌거 벗은'const char *'는 원하는 동작을하지 않기 때문에 사용할 수 없습니다. –

+1

글쎄, 나는 OP가 구조체 나 클래스를 가리키고 있다고 가정했다. 용어 * 얕은 사본 * 이외의 다른 항목에 유효합니까? –

-2

첫 번째 것은 내 마음에 오는 것은 물체를 움직이는 것입니다.

당신은 new 연산자를 사용하여 클래스의 메모리를 할당했다고합시다.

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    void destroy() 
    { 
     delete [] data; 
    } 

    A (const A& copy) 
    { 
     data = copy.data; 
    } 


    int* data 
} 

이 개체를 복사하려고합니다.포인터를 데이터에 복사하는 대신 모든 데이터를 복사하는 것이 좋습니다.

A calculateA() 
{ 
    A returnVal; 
    for (int i = 0; i < 50; i++) 
     returnVal.data[i] = i; 
    return returnVal; 
} 

이 경우에는 얕은 복사가 유리할 수 있습니다.

나는 수천 가지 다른 이유가있을 것이라고 확신합니다.

복사본을 복사 할 때 이중 삭제를 방지하려면 복사본을 null로 설정할 수 있습니다.

#include <iostream> 
#include <utility> 

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    ~A() 
    { 
     if (data) 
     delete [] data; 
    } 

    A (A& copy) 
    { 
     data = copy.data; 
     copy.data = nullptr; 
    } 

    int* data; 
}; 


int main() 
{ 
    A aVal; 
    for (int i = 0; i < 50; i++) 
     aVal.data[i] = i; 

    A anotherVal = aVal; 

    int i = 10; 
    while (i--) 
     std::cout << anotherVal.data[i]; 
} 
+0

아래 표를 설명하여 실수로부터 배울 수 있도록하십시오. –

+0

"*이 경우에는 얕은 복사가 유리할 수 있습니다. *"그리고 방금 얕은 복사가 쉽게 깨지는 방법을 설명했습니다. 귀하의 경우 여기에서'data' 배열 *을 두 번 삭제하려고 시도합니다. –

+0

그래서 내가 "할 수있다"는 질문은 "이유가 무엇인지"묻기 때문입니다. 간단한 포인터 검사만으로 쉽게 피할 수 있습니다. –

0

는 다음과 같은 예를 생각해 :

여기
shared_ptr<T> p1(new T); 
... 
shared_ptr<T> p2 = p1; 

P2는 P1의 단순 복사본입니다. 여기에 참조를 사용할 수는 있지만 반환 할 수는 없습니다.

shared_ptr<T> f() { 
    shared_ptr<T> p1(new T); 
    return p1; 
} 
+0

자동으로 이동됩니다. 물론 C++ 11에서. –

+0

두 번째 예에서는 첫 번째 예는 아니지만 첫 번째 예는 아닙니다. –

+0

맞아요.하지만 OP의 포인트는 여전히 유효합니다. 합리적인 방법으로 오브젝트를 작동 시키려면 얕은 복사가 엄격히 필요하지 않습니다. –