업데이트:

태그: ,

카테고리:



REF : 윤성우의 열혈 C++

복사 생성자

  • 생성자의 한 형태
  • 객체를 복사한다.
int main(void)
{
	SoSimple sim1(15, 20);
	SoSimple sim2=sim1;
	sim2.ShowSimpleData();
	return ;
}
  • SoSimple sim2=sim1;SoSimple sim2(sim1);과 같은 의미로 해석된다.
    1. SoSimple형 객체를 생성하고
    2. 객체의 이름은 sim2로하고
    3. sim1을 인자로 받는 생성자를 호출해 객체 생성을 완료한다.
  • 이때 호출되는게 복사생성자이다.

  • 예시
      SoSimple(const SoSimple &copy) : num1(copy.num1), num2(copy.num2)
      {
          cout<<"Called SoSimple(SoSimple &copy"<<endl;
      }
    


자동으로 삽입되는 디폴트 복사 생성자

  • 복사생성자를 정의하지 않으면, 멤버 대 멤버의 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입된다.

따라서

class SoSimple
{
	private:
		int num1;
		int num2;
	public:
		SoSimple(int n1, int n2) : num1(n1), num2(n2)
		{}
}

위 코드에는 자동으로 디폴트 복사 생성자가 삽입된다.

class SoSimple
{
	private:
		int num1;
		int num2;
	public:
		SoSimple(int n1, int n2) : num1(n1), num2(n2)
		{}
		SoSimple(const SoSimple& copy) : num1(copy.num1), num2(copy.num2)
		{}
}


### 묵시적 변환을 막는 explicit

 SoSimple sim2 = sim1;
 SoSimple sim2(sim1);
  • 위의 코드는 아래의 코드로 묵시적 변환이 일어나서 복사 생성자가 호출된다.
  • 복사생성자의 묵시적 호출을 허용하지 않기 위해선
     explicit SoSimple(const SoSimple &copy) : num1(copy.num1), num2(copy.num2)
     {
     }
    

    이렇게 선언해준다.

이렇게 명시적으로 복사생성자를 선언해준다면 앞으로 대입연산자
SoSimple sim2 = sim1;처럼 객체의 생성과 초기화가 불가능해진다.



깊은 복사와 얕은 복사

  • 디폴트 복사 생성자멤버 대 멤버의 복사를 진행한다.
  • 그리고 이러한 방식의 복사는 얕은 복사라고한다.
  • 이 경우에는, 멤버변수의 heap의 메모리 공간을 참조하면 문제를 일으킨다.
  • 멤버의 메모리를 참조해 값을 복사해 할당하는 복사이다.
  • 따라서 각 소멸자에서 두 번 메모리 할당을 해제하면 2번째에서 double free 오류를 보게된다.


깊은 복사를 위한 복사생성자의 정의

  • 각각의 객체는 포인터로 참조하는 대상까지 깊게 복사한다.
  • 클래스에 맞게 복사생성자에서 깊은 복사를 위한 코드를 작성하면 된다.


복사 생성자의 호출 시점

  1. 기존에 생성된 객체를 이용해 새로운 객체를 초기화
  2. Call-by-value 방식으로 함수 호출과정에서 객체를 인자로 전달.
  3. 객체를 반환하되, 참조형으로 반환하지 않는 경우.

이 복사생성자의 호출시점의 경우 공통적으로
객체를 새로 생성하되, 생성과 동시에 동일한 자료형의 객체로 초기화한다.


  • 1번
      SoSimple obj2 = obj1;
      //SoSimple obj2(obj1);
    


  • 2번
      void SoSimpleFunction(SoSimple ob)
      {
    
      }
      int main(void)
      {
          SoSimple obj(7);
    
          SoSimpleFunction(obj);
          //ob의 복사생성자가 호출되어 매개변수 ob에 obj의 값이 복사됨.
      }
    
  • 3번
      SoSimple SoSimpleFunction(SoSimple ob)
      {
          return (ob);//여기서 반환하면서 메모리 공간이 할당되며 ob로 초기화됨.
      }
      int main(void)
      {
          SoSimple obj(7);
    
          std::cout<<SoSimpleFunction(obj)<<std::endl;;
          //
      }
    


  • 3번과같이 객체를 반환하게되면 임시 객체가 생성되고, 복사생성자가 호출되면서 return 문에 명시된 객체가 인자로 전달된다.
  • 임시객체는 다음 행으로 넘어가면 소멸된다.
  • 참조자로 참조되는 임시객체는 바로 소멸되지 않는다.



댓글남기기