관리 메뉴

드럼치는 프로그래머

[C/C++] C++ 복사 생성자 - 1. 객체의 생성과 대입 & 2. 객체의 값에 의한 전달 본문

★─Programing/☆─C | C++

[C/C++] C++ 복사 생성자 - 1. 객체의 생성과 대입 & 2. 객체의 값에 의한 전달

드럼치는한동이 2009. 11. 27. 08:54

 ex 2. 복사 생성대입

#include <iostream>
using namespace std;

class CPoint{
private:
   int x, y;

public:
   CPoint(int a) : x(a), y(a){ }
   void Print(){ cout<<"("<<x<<", "<<y<<")"<<endl; }
};

int main(void){
   CPoint P1(3);       // 객체 생성, P1 : (3, 3)
   CPoint P2(4);       // 객체 생성, P2 : (4, 4)
   CPoint P3=P2;   // 복사 생성, P3 : (4, 4)
   CPoint P4(P2);  // 복사 생성, P4 : (4, 4)

   P1=P2;               // 객체 대입, P1 : (4, 4)

   P1.Print();
   P2.Print();
   P3.Print();
   P4.Print();

   return 0;
}

 

@ 복사 생성과 대입을 구분할 수 있도록 하자.

- 복사 생성 : 생성자(그 중에서 복사 생성자)가 동작함.

 (새로이 객체를 생성하는데, 이미 존재하는 객체를 그대로 복사함. assign이 아님.)

- 객체 대입 : 대입 연산자가 동작함.

 (이미 생성되어 존재하는 객체에 대하여 또 다른 객체를 그대로 복사함. assign.)

 

@ 복사 생성과 대입 연산의 디폴트 동작

멤버 단위 복사(member shallow copy). → 객체 안에 있는 내부 구조까지 copy하진 않는다. 얕은 레벨에서 copy.

 

 

@@ 다음 프로그램들의 문제점해결 방안을 생각해보자.

1. 객체의 선언 및 초기화 : ex) CPoint P2(P1);

 ex 3. 문자열을 다루기 위한 CString 클래스 구현

#include <iostream>
#include <cstring>  // strlen, strcpy 함

using namespace std;

class CString{
private:
   int len;       // 문자열의 길이
   char *str;  // 문자열 포인터

public:
   CString(char *s="Unknown"){
      len=strlen(s);
      str=new char[len+1];                   // 메모리 동적 할당
      strcpy(str,s);
   }
   ~CString(){ delete [] str; }             // 메모리 동적 해제
   void Print(){ cout<<str<<endl; }
};

int main(void){
   CString str1="C++ Programming";
   CString str2=str1;  // 복사 생성
   CString str3;

   str3=str1;               // 대입 연산

   str1.Print();
   str2.Print();
   str3.Print();

   return 0;
}

 

 실행은 되지만, 에러 메시지가 뜨는 이유는?

⇒ 복사 생성, 객체 대입을 통해 생성된 객체들이 모두 동일한 메모리(동적으로 생성된)를 가리키고 있다가

    객체 소멸 시, 제일 나중에 생성된 객체, str3이 소멸되면서 가리키고 있던 메모리도 해제시켜 주게 되는데,

    이 때 다음에 객체 str2가 소멸될 때는 존재하지 않는 메모리를 가리키고 있어 반환할 메모리가 존재하지 않게 되므로

    error 발생!!

  

⇒ "복사 생성자"를 이용하여 해결할 수 있다.

 

2. 객체의 값에 의한 전달 : ex) void ShowString(CString str){ ... }    // call-by-value

 ex 4.

#include <iostream>
using namespace std;

class CPoint{
private:
   int x, y;

public:
   CPoint(int a, int b) : x(a), y(b){ }
   void Print(){ cout<<"("<<x<<", "<<y<<")"<<endl; }
};

void ShowPoint(CPoint P){
   P.Print();
}

int main(void){
   CPoint P1(1,2);
   ShowPoint(P1);     // 값에 의한 객체 전달

   return 0;
}

 

 ex 5.

#include <iostream>
#include <cstring>
using namespace std;

class CString{
private:
   int len;
   char *str;

public:
   CString(char *s="Unknown"){
      len=strlen(s);
      str=new char[len+1];           // 메모리 동적 할당
      strcpy(str,s);
   }
   ~CString(){ delete [] str; }     // 메모리 동적 해제
   void Print(){ cout<<str<<endl; }
};

void ShowString(CString str){     // 값에 의한 전달
   str.Print();
}

int main(void){
   CString str1="C++ Programming";
   ShowString(str1);

   return 0;
}

 

실행은 되지만 에러가 발생하는 이유는?

⇒ str1 객체 생성 후 ShowString 함수를 호출할 때, 인자로 객체 str1을 값에 의해 넘겨주면서 str1을 고대로 복사한 객체 str 생성. 따라서 객체 str1과 객체 str은 동일한 메모리(동적으로 할당된)를 가리키게 된다.

 ShowString 함수를 모두 수행하고 block을 빠져 나오면서 지역 객체인 str 객체는 소멸되게 된다. str 객체가 소멸되면서 이 객체가 가리키고 있던 동적 메모리를 해제시켜 준다. 그리고 나중에 main 함수가 끝날 때 str1 객체가 소멸되게 되는데, 이 때 str1이 가리키고 있던 메모리는 이미 없어진 후 이므로 str1은 반환한 메모리가 없어졌으므로 error가 발생하게 되는 것이다.



⇒ "복사 생성자"를 이용하여 문제를 해결할 수 있다!!




[출처]
chapter 6. 복사 생성자 - 1. 객체의 생성과 대입 & 2. 객체의 값에 의한 전달|작성자 쩡뉴니

Comments