2017-02-08 4 views
1

저는 프로그래밍 초보자이며 복사 생성자에 대해 배우고 있습니다. 다른 소스에서 클래스 객체를 "딥 복사 (deep copy)"하여 새로운 객체의 포인터 멤버가 새로운 메모리 위치를 가리 키도록하려는 경우 복사 생성자가 유용하다는 것을 알 수 있습니다.복사 생성자 및 동적 메모리

제 질문은, 빈 복사 생성자 (EmptyCat 클래스에서 사용)와 동일한 결과를 얻는 경우 CopyCat에서와 같이 복사 생성자를 정의하는 것의 이점은 무엇입니까?

두 번째 질문은 Cat 클래스와 EmptyCat 클래스가 다르게 작동하는 이유는 무엇입니까? 그들 사이의 유일한 차이점은 EmptyCat에 빈 복사 생성자를 정의한다는 것입니다. 그러나 프로그램을 실행하면 EmptyCat에서 포인터 멤버가 새 위치를 가리키는 것을 복사 한 후 Cat 클래스에서 얕은 복사본으로 작동한다는 것을 알 수 있습니다. 나는이 프로그램을 실행하면

#include "iostream" 

class Cat 
{ 
    public: 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

class EmptyCat 
{ 
    public: 
    EmptyCat() {} 
    ~EmptyCat() {} 
    EmptyCat(EmptyCat&obj) {} 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

class CopyCat 
{ 
    public: 
    CopyCat() {} 
    ~CopyCat() {} 
    CopyCat(CopyCat&obj); 
    int GetAge() { return *itsAge; } 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

CopyCat::CopyCat(CopyCat & obj) 
{ 
    itsAge = new int; 
    *itsAge = obj.GetAge(); 
} 

int main() 
{ 
    Cat Garfield; 
    Cat Kitty(Garfield); 

    std::cout << "Memory addresses for the objects' <itsAge> member:" << std::endl; 
    std::cout << "Garfield and Kitty (Class Cat):" << std::endl; 
    Garfield.GetMem(); 
    Kitty.GetMem(); 

    EmptyCat Meow; 
    EmptyCat Purr(Meow); 

    std::cout << std::endl << "Meow and Purr (Class EmptyCat):" << std::endl; 
    Meow.GetMem(); 
    Purr.GetMem(); 

    CopyCat Fluffy; 
    CopyCat Felix(Fluffy); 

    std::cout << std::endl << "Fluffy and Felix (Class CopyCat):" << std::endl; 
    Fluffy.GetMem(); 
    Felix.GetMem(); 

    system("pause"); 
    return 0; 
} 

나는이 얻을 :

Memory addresses for the objects' <itsAge> member: 
Garfield and Kitty (Class Cat): 
00BBDA60 
00BBDA60 

Meow and Purr (Class EmptyCat): 
00BB46A0 
00BB8280 

Fluffy and Felix (Class CopyCat): 
00BB82B0 
00BBE8A0 
Press any key to continue . . . 
+3

클래스가 메모리를 누설하므로 실제로는 좋은 예제가 아닙니다. –

+0

복사 생성자의 동작에 초점을 맞추어 가능한 한 간단하게 만들고 싶습니다. – SVG

+0

그러나 그렇게함으로써 재미있는 모든 것을 놓치고 있습니다. 소멸자가 할당을 삭제해야한다면, 당신은 즉시 3 개의 모든 규칙을 발견 할 것입니다. –

답변

0

제 질문은 빈 복사 생성자 (EmptyCat 클래스에서 사용)와 동일한 결과를 얻는 경우 제 CopyCat 클래스에서와 같이 복사 생성자를 정의 할 때의 이점은 무엇입니까?

같은 결과가 나지 않습니다. CopyCat은 새 메모리를 할당합니다. 은 이전 클래스의 값을 복사합니다. EmptyCat은 새 메모리 만 할당하지만 값은 복사하지 않습니다.

내 두 번째 질문은 클래스 Cat과 클래스 EmptyCat이 다르게 작동하는 이유는 무엇입니까? 그들 사이의 유일한 차이점은 EmptyCat에 빈 복사 생성자를 정의한다는 것입니다. 그러나 프로그램을 실행하면 EmptyCat에서 포인터 멤버가 새 위치를 가리키는 것을 복사 한 후 Cat 클래스에서 얕은 복사본으로 작동한다는 것을 알 수 있습니다.

필요할 때 컴파일러가 하나를 생성합니다 있도록, 복사 생성자를 선언하지 않은 Cat에서

. 기본 복사 생성자는 원본에서 구성원 별 복사본을 만듭니다. 귀하의 경우 포인터가 복사되어 원본과 동일한 주소가 저장됩니다.

EmptyCat에는 사용자 정의 복사 생성자가 있습니다. 그러나 포인터 멤버를 처리하지 않으므로 기본값이 사용됩니다.

int * itsAge = new int; 

이것은 int을 새로 할당하고 다른 포인터 값을 가져옵니다.

+0

귀하의 대답에 따라 몇 가지 사항을 변경했으며 비공개로 정의 된 복사 생성자가 어떻게 작동하는지 발표 할 수있었습니다. 빈 정의가있는 복사 생성자는 실제로 복사 생성자가 아니며 복사하지 않으며 실제로는 새 객체 생성으로 작동합니다. 그것은 클래스 정의를 기반으로 새로운 객체를 생성합니다. 그래서 클래스 정의에'int * itsAge = new int;'문을 가지고 있기 때문에 혼란스러워합니다. (빈 복사 생성자가 새로운 객체). – SVG

+0

좀 더 연구를했는데, 복사 된 생성자가 없을 때 사용되는 암시 적 복사 생성자가 다음과 같습니다. 'Class :: Class (const Class & object) : x (따라서 암시적인 복사본 생성자는 비효율적으로 정의 된 것 이상을 수행합니다. – SVG

0

당신이하고 빈 복사 생성자없이 동일한 동작을 받고 있지 않습니다. EmptyCat(EmptyCat& obj) { }는 아무 것도하지 않습니다.

CopyCat(CopyCat& obj) { 
    itsAge = new int; 
    *itsAge = obj.GetAge(); 
} 

동적 새로운 int을 할당하고 상기 obj의 값을 할당한다.

0

딥 복사와 얕은 복사는 구조와 원시 포인터 만있는 C 개념입니다. 포인터를 소유 할 수 있습니다.이 경우 복사본이 깊어 야하거나 공유 될 수 있습니다.이 경우 복사본이 얕습니다 (malloc로 할당 된 경우이를 해제 할 때주의해야합니다).

C++에서 new는 이제 효과적으로 사용되지 않습니다. 우리는 "소유 포인터"와 "공유 포인터"인 유일한 포인터를 가지고 있습니다. 그러나 포인터는 비교적 드뭅니다. 클래스의 배열 멤버는 std :: vectors이고, 문자열 멤버는 std :: strings입니다. 그리고 사본은 자동으로 깊어집니다 (얕은 사본이 필요한 경우 참조를 사용합니다).

포인터는 나무 나 그래프와 같이 비교적 드문 경우를 위해 뒤로 잡혀 있습니다.