250x250
Notice
Recent Posts
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
관리 메뉴

일상 코딩

[C++/9.11] 대입"=" 연산자 오버로딩, 깊은 복사, 얕은 복사 문제점 및 해결 방법 본문

C++/따배C++ 09강 연산자 오버로딩

[C++/9.11] 대입"=" 연산자 오버로딩, 깊은 복사, 얕은 복사 문제점 및 해결 방법

polarcompass 2021. 10. 31. 14:26
728x90
#include <iostream>
#include <cassert>
using namespace std;

class MyString
{
    //private:
public:
    char *m_data = nullptr;
    int m_length = 0;

public:
    // 문자열 받고 있는 생성자
    MyString(const char *source = "")
    {
        assert(source);
        // 문자열 길이 함수
        //  +1 을 한 이유는 문자열 끝에 문자열 끝을 나타내기 위한 '\0'을 넣기 위함.
        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';
    }

    // delete
    // 만약에 복사 생성자가 구현이 안되어있을 경우 
    // 얕은 복사를 막는 차선책
    // 가장 좋은것은 복사 생성자를 만드는 것이 가장 좋다.
    // MyString(const MyString &source) = delete;

    // 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;
    }

    // 대입 연산자
    // Assignment Operator
    MyString &operator=(const MyString &source)
    {
        // default copy constructor 코드
        // 동적 할당 메모리로 되어있을 경우엔 이렇게하면 문제가 생김.
        // this->m_data = source.m_data;
        // this->m_length = source.m_length;

        cout << "Assignment operator " << endl;

        // hello = hello 와 같은 코드를 방지하기 위한 방어 코드
        // this의 주소와 &source의 주소를 비교하여 같으면 그냥 넘김.
        if (this == &source) //prevent self-assignment
            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;

        return *this;
    }

    // 소멸자
    ~MyString()
    {
        delete[] m_data;
        cout << "delete MyString" << endl;
    }

    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 = hello;
        cout << (int *)copy.m_data << endl;
        cout << copy.getString() << endl;
    }

    cout << hello.getString() << endl;

    // 구분선
    for (int i = 0; i < 20; i++)
        cout << "-";
    cout << endl;

    // copy constructor 호출됨
    MyString str1 = hello;
    // 코딩시 MyString str1(hello);로 작성시 동일하고 덜 헷갈리게 된다.

    MyString str2;
    // assignment operator 호출됨.
    str2 = hello;

    return 0;
}
728x90