개인 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요 ;)
MyString(const MyString& source)
{ // 메모리를 다시 할당받고 값을 다시 복사하는 걸 deep copy
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;
}
이 코드의 경우에는 단순히 복사생성자에서 포인터의 주소만 가져오는 것이 아니라,
new char을 통해 메모리를 할당받고
새로운 m_data에 복사하는 객체의 배열 요소들을 for문을 통해 가져옵니다.
이러한 복사 방식을 deep copy라고 합니다.
MyString& operator = (const MyString& source) // 대입 연산자
{
//shallow copy
/*this->m_data = source.m_data;
this->m_length = source.m_length;*/
cout << "Assignment operator " << endl;
if (this == &source) // self-assignment를 막아서
return *this; // 자신을 return하고 끝냄
delete[] m_data; // 다른 instance를 대입하기 전에 이미 주소에 값이 있을 수 있음
m_length = source.m_length;
if (source.m_data != nullptr) // 복사하려는 것이 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;
}
위에 있는 코드는 특정 클래스에 다른 멤버를 대입할 때 사용하는 대입 연산자입니다.
클래스를 설계할 때 대입 연산자를 만들지 않으면 shallow copy로 멤버를 복사하도록 visual studio는 기본 설계가 되어있는 것 같아요.
코드를 한 줄씩 설명 드리자면 첫 번째 if문은 자기 자신을 복사하는 것을 방지하는 것입니다.
사람이 볼 때는 자신에게 왜 자기를 또 복사하지..? 하고 넘어가면 그만인데,
프로그램이나 컴파일러의 입장에서는 꽤 복잡한 문제로 번지나봐요.
그래서 복사하려는 instance의 주소가 자신과 같으면 그냥 자기 자신을 return하고 생성자를 끝내버립니다.
그 아랫줄에 delete[]같은 경우는, 일단 대입을 하려면 초기화가 된 instance이고,
그렇다면 해당 주소에 이전에 저장된 값이 있을 가능성이 있겠죠?
때문에 이를 막기 위해 해당 메모리를 delete[]를 통해 완전히 씻어냅니다.
그 다음부터는 대입하려는 instance의 길이를 입력받고,
m_data를 순서대로 복사하는 과정으로 대입 연산자가 마무리됩니다.
int main()
{
MyString hello("Hello");
MyString str1 = hello;
MyString str2;
str2 = hello;
return 0;
}
위 코드블록에서 보시면,
hello라는 이름의 멤버에 "Hello"라는 문자열을 입력하여 초기화시켜주고,
그 다음에는 str1이라는 멤버를 초기화하면서 hello를 대입해줍니다.
우리는 위에서 분명 대입 연산자를 설정했지만, str1의 경우는 값을 정하는 초기화 단계이기 때문에 대입 연산자가 아니라 copy constructor가 호출됩니다. 이점 주의하세요!
반면 그 아랫줄에 있는 str2는 초기화가 된 이후에, 그 아랫줄에서 hello를 대입하니까 대입 연산자가 호출됩니다.
MyString(const MyString& source) = delete; // shallow copy가 되는걸 막는 차선책?
작업 시간이 부족하거나 하면 모든 클래스에 일일이 copy constructor를 만들 여유가 없을 수도 있을텐데,
그럼에도 shallo copy가 발생하는 걸 막는 차선책이 위에 있는 코드블록처럼 아예 copy constructor 자체를 막는 방법입니다.
하지만 가장 좋은 건 copy constructor를 설정하는 것이겠죠?
'Information Technology > C++' 카테고리의 다른 글
[C++] 입출력 연산자 오버로딩 (0) | 2019.11.15 |
---|---|
[C++] 산술 연산자 오버로딩 (0) | 2019.11.15 |
[C++] std::move(2) (0) | 2019.11.15 |
[C++] std::move(1) (0) | 2019.11.15 |
[C++] 이동 생성자와 이동 대입 (0) | 2019.11.15 |