본문 바로가기
C++

#2. 복사 생성자의 호출 시점

by imagineer_jinny 2022. 2. 4.
  • 복사 생성자의 호출 시점
  • 복사 생성자의 호출시점은 크게 세 가지로 구분
    1. 기존에 생성된 객체를 이용해 새로운 객체를 초기화 하는 경우
    2. Call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우
    3. 객체를 반환하되, 참조형으로 반환하지 않은 경우

 

1. 기존에 생성된 객체를 이용해 새로운 객체를 초기화 하는 경우

Person man1("Lee jinny", 29);
Person man2 = man1;
#include <iostream>
using namespace std;

class Sample {
	int x;
public:
	Sample(int n) : x(n)
	{ }
	Sample(const Sample &copy) : x(copy.x)
	{
		cout << "복사 생성자 호출" << endl;
	}
};

int main() {

	Sample a(7);
	cout << "Before copy" << endl;
	Sample b = a; // b 객체의 복사 생성자 호출
	cout << "After copy" << endl;

	return 0;
}

a라는 기존의 생성된 객체를 이용해 새로 생성된 b 객체의 복사 생성자를 호출하여 객체끼리 멤버 간 복사가 일어남

 

 

2. Call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우

 

#include <iostream>
using namespace std;

class Sample {
	int x;
public:
	Sample(int n) : x(n)
	{ }
	Sample(const Sample &copy) : x(copy.x)
	{
		cout << "복사 생성자 호출" << endl;
	}
};

void Callbyvalue(Sample sp) { // 기존 객체를 인자로 받아 sp 객체의 복사 생성자 호출

	cout << "After copy_callbyvalue" << endl;
}

int main() {

	Sample a(7);
	cout << "Before copy_callbyvalue" << endl;
	Callbyvalue(a);

	return 0;
}

 Callbyvalue 함수의 매개변수인 sp가 기존 객체 a를 인자로 받아서 sp 객체의 복사 생성자를 호출하여 객체끼리 멤버 간 복사가 일어남

 

3. 객체를 반환하되, 참조형으로 반환하지 않은 경우

 

#include <iostream>
using namespace std;

class Sample {
	int x;
public:
	Sample(int n) : x(n)
	{ }
	Sample(const Sample &copy) : x(copy.x)
	{
		cout << "복사 생성자 호출" << endl;
	}
};

Sample Returnvalue(Sample sp) {

	cout << "After copy_callbyvalue" << endl;

	cout << "Before copy_return" << endl;
	return sp;
}

int main() {

	Sample a(7);
	cout << "Before copy_callbyvalue" << endl;
	Sample b = Returnvalue(a);
	cout << "After copy_return" << endl;

	return 0;
}

 

 Returnvalue 함수에서 Call by value 방식의 함수 호출 과정에서 객체를 인자로 전달하는 경우를 통해 sp 객체가 복사되어 생성되고 이 sp 객체를 반환하다. 여기서 중요한 것은 반환 시에 임시 객체를 생성하고 이 임시 객체는 sp 객체를 인자로 전달받아 임시 객체의 복사 생성자를 호출함

 

임시객체 = 지역변수 -> 메모리 잡음

레퍼런스(&) 안 붙이면 복사가 되니까 복사 생성자가 불린다

 

기본 생성자, 복사 생성자는 자동으로 생성됨

 

출처: [정보] 복사 생성자의 호출 시점 (tistory.com)

 

 

이 그림이 중요! 한번 읽어보고 이해하기

 

 

  • 이동 생성자와 복사 생성자
    • 이동 생성자는 메모리를 따로 잡지 않음 (얕은 복사를 씀)
    • 복사 생성자는 기존의 것도 남아 있는데 메모리를 따로 잡음

 

new는 동적 할당을 하는 것이고 힙 공간에 메모리를 잡음

즉, 운영체제에 요청 들어갔다 나오는 것인데 이런 것들은 interrupt가 생김

그런데 운영체제에 부탁하는 것 자체가 꽤 오래 걸림

 

new 많이 하면 성능 안좋을 수 있다. 그래서 new를 하는 복사생성자의 문제가 조금씩 나타남

 

그래서 나타난게

new를 안하는 버전의 생성자가 이동생성자!

 

성능상의 이슈가 덜함!

 

근데, new를 안하고 어떻게 객체 생성을 하지?

같이 가리키고 있던 것 중에 하나를 끊어버림

저 그림에서 문제가 되었던게 두개의 포인터가 하나를 가리키기 때문에 문제였으니까

하나를 그냥 끊어버림. 즉, 집주인 나오라고 하고 내가 들어가서 산다는 개념이 이동생성자!

 

 

복사생성자의 경우 메모리 하나 잡고(new 해서) 자기껄로 값을 복사해오는것이고

이동생성자는 원래 있던걸 재활용해서 쓴다. 

 

현실은 복사, 이동생성자를 적절히 배합해서 쓰고 일반적으로는 이동생성자가 성능이 조금 더 좋다!

댓글