대입 연산자 오버로딩, 복사 생성자

Jaemyeong Lee·2024년 8월 20일
0

FastCampusC++

목록 보기
65/78

C++ 대입 연산자와 복사 생성자 분석 및 정리

이번 포스트에서는 C++에서 대입 연산자와 복사 생성자의 동작 방식에 대해 예제 코드를 통해 자세히 알아보겠습니다. 이를 통해 객체의 복사와 관련된 메모리 문제를 어떻게 해결할 수 있는지 학습할 것입니다.

코드 설명

#pragma once
#pragma warning(disable: 4996)
#include <iostream>

class GoodPerson
{
private:
    float _weight;
    float _height;
    char* _name;

public:
    GoodPerson() {}
    GoodPerson(float weight, float height, const char* name)
        : _weight(weight), _height(height), _name(new char[strlen(name) + 1])
    {
        strcpy(_name, name);
    }

    GoodPerson(const GoodPerson& person)
        : GoodPerson(person._weight, person._height, person._name)
    {

    }

    ~GoodPerson()
    {
        delete[] _name; // 복사된 객체들이 중복 삭제 될 위험이 있음
    }

    GoodPerson& operator=(const GoodPerson& person)
    {
        _weight = person._weight;
        _height = person._height;
        delete[] _name;

        _name = new char[strlen(person._name) + 1];
        strcpy(_name, person._name);
        return *this;
    }

    void print() const
    {
        using namespace std;
        cout << _name << endl;
        cout << _weight << endl;
        cout << _height << endl;
    }
};

주요 개념과 설명

  1. #pragma once: 이 지시어는 헤더 파일이 여러 번 포함되는 것을 방지합니다. 중복 포함으로 인한 컴파일 오류를 방지하는 역할을 합니다.

  2. #pragma warning(disable: 4996): 컴파일러 경고 4996을 비활성화합니다. 이는 strcpy와 같은 "안전하지 않은" C 함수에 대한 경고를 억제하는 데 사용됩니다.

  3. 클래스 GoodPerson의 멤버 변수:

    • _weight_height는 각각 float 타입의 몸무게와 키를 저장합니다.
    • _namechar* 타입으로 이름을 저장하는데, 동적 메모리 할당을 사용하여 저장합니다.
  4. 생성자:

    • 기본 생성자: 매개변수 없이 객체를 생성합니다.
    • 매개변수가 있는 생성자: 객체를 초기화하며, 이름에 대한 메모리를 동적 할당하고 strcpy로 복사합니다.
    • 복사 생성자: 다른 GoodPerson 객체를 복사하여 새 객체를 생성합니다. 이때 중복된 코드 작성을 피하기 위해, 위임 생성자를 사용하여 초기화합니다.
  5. 소멸자:

    • 동적으로 할당된 메모리를 해제합니다. 하지만 복사된 객체들이 같은 메모리 주소를 참조하는 경우, 동일한 메모리를 중복으로 해제할 위험이 있습니다.
  6. 대입 연산자:

    • 대입 연산자가 호출될 때, 기존에 할당된 메모리를 해제한 후, 새로 동적 할당하여 값을 복사합니다. 이를 통해 메모리 누수를 방지하고 안전하게 객체를 복사할 수 있습니다.
  7. print 함수:

    • 객체의 이름, 몸무게, 키를 출력합니다.

main 함수 설명

int main()
{
    int a = 1;
    int b = a; // 복사 생성자
    a = b;  // 대입 연산자

    func(a); // 복사

    GoodPerson goodPerson0 = { 46.f, 153.f, "David Daehee Kim" };
    GoodPerson goodPerson1 = goodPerson0;
    GoodPerson goodPerson2;
    goodPerson2 = goodPerson0;

    goodPerson0.print();
    goodPerson1.print();
    goodPerson2.print();
}
  1. 기본 자료형의 복사:

    • int a = 1;에서 ba의 값을 복사받습니다. 이는 복사 생성자의 개념과 유사합니다.
    • a = b;에서는 ab의 값을 대입하며, 이는 대입 연산자의 개념과 유사합니다.
  2. 객체의 복사:

    • GoodPerson goodPerson0은 이름, 몸무게, 키로 초기화된 객체를 생성합니다.
    • GoodPerson goodPerson1 = goodPerson0;은 복사 생성자를 사용하여 goodPerson0을 복사한 새로운 객체를 생성합니다.
    • GoodPerson goodPerson2;로 기본 생성자를 호출한 후, goodPerson2 = goodPerson0;로 대입 연산자를 통해 goodPerson0의 데이터를 goodPerson2에 복사합니다.
  3. 출력:

    • 세 객체 모두 동일한 값을 가지므로 동일한 출력이 세 번 반복됩니다.

문제점 및 개선점

위 코드에서 복사 생성자와 대입 연산자는 동적 메모리 할당을 잘 처리하고 있지만, 소멸자에서의 중복 메모리 해제 문제가 발생할 수 있습니다. 이 문제는 깊은 복사를 통해 해결할 수 있습니다.

복사 생성자와 대입 연산자를 정의할 때, 동적 메모리를 안전하게 관리하는 것이 중요합니다. 특히, 복사할 때마다 새로운 메모리를 할당하고, 기존 메모리를 안전하게 해제하는지 확인해야 합니다.

결론

이 포스트에서는 C++의 복사 생성자와 대입 연산자에 대해 살펴보았습니다. 객체의 복사 시 메모리 관리의 중요성을 이해하고, 올바르게 복사 생성자와 대입 연산자를 구현하는 방법을 익히는 것이 중요합니다. 이번 예제를 통해 메모리 관리와 객체 복사에 대해 명확히 이해할 수 있기를 바랍니다.

이제 이 개념들을 복습하고 실습하여 완전히 익혀보세요!

profile
李家네_공부방

0개의 댓글