본문 바로가기

C++

C++에서 객체를 저장하는 vector의 원리

[ how to store objects or object pointers in vectors ]

C++ 초심자의 경우, vector에 객체 혹은 객체에 대한 포인터를 담을 때 어떠한 원리로 담기는 지는 잘 와닿지 않습니다.

저도 vector<pointer형> vectorName(길이, new 자료형());

식으로  vector을 선언할 떄 생성자가 한 번만 호출되는 것이 의아하고 이해가 안되었었기에 글로 다시 한 번 남깁니다.


기본적인 vector 의 생성 예시는 다음과 같습니다.

vector<자료형> 변수명(자료 개수)

vector<자료형> 변수명(자료 개수, 초깃값)


Point라는 클래스가 있고 이 클래스는 생성자 2가지가 존재한다고 합시다.

1. Point()

2. Point(int x, y)


그 경우 vector를 생성할 수 있는 예시는 다음과 같습니다.


vector<Point> v1(5);    

//5개의 Point 객체를 담는 vector v1 생성, 이 때 default 생성자로 5개 생성됨.


vector<Point> v2(5, Point(10,10));

//Point(10,10)을 생성하고 이 익명 객체를 바탕으로 5번의 복사 생성자를 호출하여 vector의 각 칸을 초기화함.


vector<Point*> v3(5);

//NULL pointer 5개로 vector의 각 칸을 초기화함.


vector<Point* v4(5, new Point(20,20);

//Point(20,20)을 이용해 동적으로 Point객체를 생성하고 그 객체에 대한 주소값을 이용해 Point pointer를 초기화함.


위에서 첫 번째와 두 번째는 맨 위에서 얘기한 기본적인 사용법과 일치하고,

세 번째 네 번째가 조금 어렵다.

세 번째의 경우 pointer는 default 값이 NULL 이라 그렇게 되는 것이고,

네 번째의 경우에는 다소 혼란스러울 수 있는데, 결과적으로 객체는 하나가 생성되고, 따라서 생성자든 복사생성자든 상관없이, 생성자만 한 번 생성되고, vector의 각 칸(pointer임. )그 생성된 객체의 주소를 저장할 뿐이다.


vector<Point> v2(5, Point(10,10));

즉 위의 코드에서는 각 vector의 칸들에게 넣을 객체의 원본을 생성자로 생성하고,

vector의 각 칸은 방금 생성한 익명 객체 (anonymous object)를 이용하여 복사생성자로 생성된다.

따라서 생성자 1번, 복사생성자 5번이 호출된다.


vector<Point* v4(5, new Point(20,20);

하지만 위의 코드에서는 new Point(20,20)에 의해 객체가 생성자를 이용해 하나 동적으로 생성되고,

vecotr의 각 칸은 방금 생성한 익명 객체 (anonymous object)의 주소값을 저장하는 pointer 변수가 저장된다.

따라서 vector의 각 칸은 그저 주소값을 저장하는 pointer일 뿐이므로, 생성자는 단 한 번만 호출된다. 


전체 소스 코드가 아래와 같다고 합시다.


#include 
#include 
using namespace std;

class Point
{

public:
	int x, y;
public:

	Point(int x = 0, int y = 0)
	{
		cout << "( "< x = x;
		this->y = y;
	}

	Point(const Point& p)
	{
		this->x = p.x;
		this->y = p.y;
		cout << "복사생성자!" << endl;
	}
	
};

int main()
{
	//하나를 생성하고 걔를 이용해 각 칸마다 복사 생성자
	vector v2(5, Point(10,10));
	cout << "===================" << endl;
	vector v4(5, new Point(20, 20));
	//얘는 왜 생성자 하나만 호출 돼?
	//-> 그 객체에 대한 주소값을 각 포인터 변수들이 받는 것일 뿐!!
	cout << "===================" << endl << endl;
	cout <<"!헷갈림 주의!" << endl;
	cout << "Point의 pointer형을 저장하는 vector v4의 0번 인덱스에 위치한 pointer가 참조하는 Point 객체의 주소값" << endl;
	cout << &(*v4[0]) << endl;
	cout << "Point의 poiner형을 저장하는 vector v4의 1번 인덱스에 위치한 pointer가 참조하는 Point 객체의 주소값" << endl;
	cout << &(*v4[1]) << endl;

	cout << "즉 모두 같은 Point 객체를 참조한다." << endl;

}


Output



설명한 바와 같이 

vector v2(5, Point(10,10));

는 한 번의 생성자와 5번의 복사생성자가 호출되었고,

vector v4(5, new Point(20, 20));

한 번만 생성자가 호출되고, 주소값 출력결과를 보아 벡터 내의 각 칸의 pointer들은 모두 방금 생성된 같은 객체의 주소를 저장한다는 것을 알 수 있다.