동적할당된 메모리에 대한 포인터변수를 멤버로 가지고 있는 클래스는
복사하거나 대입할때 깊은복사,얕은복사에 따라 복사생성자,대입연산자구현이 까다로워진다.

기본 복사생성자는 주소값을 복사해준다.

동적메모리할당을 할때는 주의해야한다.

주소값만 복사해주는것을 얕은 복사라고한다.
얕은 복사는 주소값만 복사해주기에 동적할당된 메모리를 반납하게되면 이슈가 생길 수 있다.

주소값을 복사하는대신 메모리를 다시할당 받는것은 깊은 복사라고한다.
다시 주소를 할당받기에 문제가 없다.

변수가 만들어지는순간엔 복사생성자가 실행된다.
이미 있는 변수에 대입하는건 대입 연산자가 실행된다.

 

논리를 잘이해하자 자바등 어느 언어든지 동적메모리할당,반납은 있다.

#include <cassert>
#include <iostream>

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';
	}
	
	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) {

		//shallow copy;
		//this->m_length = source.m_length;
		//this->m_data = source.m_data;
		
		cout << "Assignment operator" << endl;

		//자기자신을 대입했을때
		if (this == &source)
			return *this;
	
		//이미 메모리를 가지고 있을 수 있다.
		delete[] m_data;

		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() {
		delete[] m_data;
	}

	char* getString() { return m_data; }
	int getLength() { return m_length; }
};

int main()
{

	MyString hello("Hello");

	cout << (int*)hello.m_data << endl;
	cout << hello.getString() << endl;

	{
		//복사생성자 주소값을 복사해준다.
		MyString copy;
		copy = hello;
		cout << (int*)copy.m_data << endl;
		cout << copy.getString() << endl;
		//scope를 나갈때 메모리를 반납한다.
	}

	cout << hello.getString() << endl;
	return 0;
}

+ Recent posts