본문 바로가기

개발공부/C++

얕은 복사와 깊은 복사

#include <iostream>
#include <cassert>

using namespace std;

class MyString
{
public:
	char* m_data = nullptr;
	int m_length = 0;
public:
	MyString(const char* source = "")
	{
		assert(source);
		m_length = std::strlen(source) + 1;
		m_data = new char[m_length];

		for (int i = 0; i < m_length; ++i)
		{
			m_data[i] = source[i];
		}
		m_data[m_length - 1] = '\0';
	}
	char* getString()
	{
		return m_data;
	}
	int getLength()
	{
		return m_length;
	}
	~MyString()
	{
		delete[] m_data;
	}
};

int main()
{
	MyString hello("hello");
	
	cout << (int*)hello.m_data << endl;
	cout << hello.getString() << endl;
	{
		MyString copy = hello;
		cout << (int*)copy.m_data << endl;
		cout << copy.getString() << endl;
	}
    //위 스코프를 빠져나가면서 hello가 할당받은 메로리를 해제해버린다.
        cout << hello.getString() << endl;
}
006AF320
hello
006AF320
hello
硼硼硼硼硼硼硼硼^妊뺓

디버그모드로 추적해보면 copy는 스코프를 빠져나가면서 소멸자(~MyString())를 읽어드린다. 그때 m_data는 이미 지워지고 없는데 hello가 다시 m_data에 접근하니 이상한 값이 출력되는 것이다.

default copy constructor는 다음과 같이 생겼다.(컴파일러가 만들어서 넣어준다.)

//shallow copy
*this->m_data = source.m_data;
this->m_length = source.m_length;

비슷하지만 조금 다른 대입연산자를 오버로딩해보자.

#include <iostream>
#include <cassert>

using namespace std;

class MyString
{
public:
	char* m_data = nullptr;
	int m_length = 0;
public:
	MyString(const char* source = "")
	{
		assert(source);
		m_length = std::strlen(source) + 1;
		m_data = new char[m_length];

		for (int i = 0; i < m_length; ++i)
		{
			m_data[i] = source[i];
		}
		m_data[m_length - 1] = '\0';
	}
	//copy constructor
	MyString(const MyString& source)
	{
		cout << "copy constructor " << endl;
		m_length = source.m_length;
		if (source.m_data != nullptr)
		{
			m_data = new char[m_length];
			//얕은 복사와 달리 다시 메모리를 할당받는다.(깊은복사)
			for (int i = 0; i < m_length; ++i)
			{
				m_data[i] = source.m_data[i];
				//데이터를 전부 복수중이다.(깊은복사)
			}
		}
		else
		{
			m_data = nullptr;
		}
	}
	//대입연산자 오버로딩
	MyString& operator = (const MyString& source)
	{
		cout << "Assignment operator" << endl;
		if (this == &source)//prevent self=assignment
		{
			return *this;
		}
		delete[] m_data;
		if (source.m_data != nullptr)
		{
			m_data = new char[m_length];

			for (int i = 0; i < m_length; i++)
			{
				m_data[i] = source.m_data[i];
			}
		}
		else
		{
			m_data = nullptr;
		}
		return *this;
	}
	char* getString()
	{
		return m_data;
	}
	int getLength()
	{
		return m_length;
	}
	~MyString()
	{
		delete[] m_data;
	}
};

int main()
{
	MyString hello("hello");
	
	//cout << (int*)hello.m_data << endl;
	//cout << hello.getString() << endl;
	//{
	//	MyString copy = hello;
	//	cout << (int*)copy.m_data << endl;
	//	cout << copy.getString() << endl;
	//} 
	//cout << hello.getString() << endl;
	return 0;
}

'개발공부 > C++' 카테고리의 다른 글

형변환을 오버로딩하기  (0) 2019.10.23
키워드 : friend  (0) 2019.10.23
정적 멤버  (0) 2019.10.23
다양한 반환 값들  (0) 2019.10.22
다중포인터와 동적 다차원 배열  (0) 2019.10.22