얕은 복사와 깊은 복사

shinyeongwoon·2022년 11월 22일
0

C++

목록 보기
5/10

얕은 복사 shallow copy

객체 복사 시 객체의 멤버를 1:1로 복사
객체의 멤버 변수에 동적 메모리가 할당된 경우 -> 사본은 원본 객체가 할당 받은 메모리를 공유하는 문제 발생

깊은 복사 deep copy

객체 복사 시 객체의 멤버를 1:1로 복사
객체의 멤버 변수에 동적 메모리가 할당된 경우

  • 사본은 원본이 가진 메모리 크기 만큼 별도로 동적 할당
  • 원본의 동적 메모리에 있는 내용을 사본에 복사

완전한 형태의 복사

  • 사본과 원본은 메모리를 공유하는 문제 없음

복사 생성자

copy constructor? 객체의 복사 생성 시 호출되는 특별한 생성자
특징)
한 클래스에 오직 한 개만 선언 가능
복사 생성자는 보통 생성자와 클래스 내에 중복 선언 가능
모양 -> 클래스에 대한 참조 매개 변수를 가지는 독특한 생성자

class Circle{
	....
    Circle(const Circle& c) // 복사 생성자 선언
    ....
};

Circle::Circle(const Circle& c){ //복사 생성자 구현

}

Circle 의 복사 생성자와 객체 복사

#include <iostream>
#include <string>

using namespace std;

class Circle{
private:
  int radius;
public:
  Circle(const Circle& c);
  Circle(){ radius = 1; }
  Circle(int radius){ this -> radius = radius;}
  double getArea(){
    return 3.14*radius*radius;
  }
};

Circle::Circle(const Circle& c){
  this -> radius = c.radius;
  cout << "복사 생성자 실행" << radius << endl;
}

int main(){
  Circle src(30);//일반 생성자 호출
  Circle dest(src); // 복사 생성자 호출
  cout << "원본의 면적" << src.getArea() << endl;
  cout << "사본의 면적" << dest.getArea() << endl;
}

결과
복사 생성자 실행 30
원본의 면적 2826
사본의 면적 2826

디폴트 복사 생성자

복사 생성자가 선언되어 있지 않는 클래스

  • 컴파일러는 자동으로 디폴트 복사 생성자 삽입
class Circle{
	int radius;
public:
	Circle(int r);
    double getArea();
};
Circle dest(src); //복사 생성, Circle(const Circle&)호출

디폴트 복사 생성자

Circle::Circle(const Circle& c){
	this -> radius = c.radius;
    //원본 객체 c의 각 멤버를 사본(this)에 복사한다.
}

얕은 복사 생성자를 사용하여 프로그램이 비 정상 종료 되는 경우

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

class Person{
  char* name;
  int id;
public:
  Person(int id,const char* name);
  ~Person();
  void changeName(const char* name);
  void show(){ cout << id << '.' << name << endl;}
};

Person::Person(int id, const char* name){
  this -> id = id;
  int len = strlen(name);
  this -> name = new char[len + 1];
  strcpy(this -> name,name);
}

Person::~Person(){
  if(name)
    delete [] name;
}

void Person::changeName(const char* name){
  if(strlen(name) > strlen(this -> name))
    return;
  strcpy(this->name,name);
}

int main(){
  Person father(1,"Kitae");
  Person daughter(father);

  cout << "dauhter 객체 생성 직후 ----" << endl;
  father.show();
  daughter.show();

  daughter.changeName("Grace");
  cout << "dauhter 이름을 Grace로 변경 후  -----" << endl;
  father.show();
  daughter.show(); 

  return 0;

}

에러 발생

깊은 복사 예제

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

class Person{
  char* name;
  int id;
public:
  Person(int id,const char* name);
  Person(const Person& person);
  ~Person();
  void changeName(const char* name);
  void show(){ cout << id << '.' << name << endl;}
};

Person::Person(int id, const char* name){
  this -> id = id;
  int len = strlen(name);
  this -> name = new char[len + 1];
  strcpy(this -> name,name);
}

Person::Person(const Person& person){
  this -> id = person.id;
  int len = strlen(person.name);
  this -> name = new char[len + 1 ];
  strcpy(this -> name,person.name);
  cout << "복사 생성자 실행 , 원본 객체의 이름" << this -> name << endl;
}


Person::~Person(){
  if(name)
    delete [] name;
}

void Person::changeName(const char* name){
  if(strlen(name) > strlen(this -> name))
    return;
  strcpy(this->name,name);
}

int main(){
  Person father(1,"Kitae");
  Person daughter(father);

  cout << "dauhter 객체 생성 직후 ----" << endl;
  father.show();
  daughter.show();

  daughter.changeName("Grace");
  cout << "dauhter 이름을 Grace로 변경 후  -----" << endl;
  father.show();
  daughter.show(); 

  return 0;

}



묵시적 복사 생성에 의해 복사 생성자가 자동 호출 되는 경우


void f(Person person){ //값에 의한 호출
	person.chageName("dummy1");
}

Person g(){
	Person mother(2,"Jane");
    return mother;
}

int main(){
	Person father(1,"Kitae");
    Person son = father; //복사 생성자 호출 : 객체로 초기화 하여 객체가 생성 될 때
    f(father); //복사 생성자 호출 : 값에 의한 호출로 객체가 전달 될때
    g(); //복사 생성자 호출 //함수에서 객체를 리턴할 때, mother의 복사본 생성, 복사본의 복사 생성자 호출
}

0개의 댓글