Player.h - 소멸자와 메모리 관리

#pragma once
#include <iostream>

using namespace std;

class Player
{
private:
    int _num;

public:
    Player(int num) : _num(num)
    {
        cout << "Constructor : " << _num << endl;
    }

    ~Player() // 소멸자, 항상 파라미터가 없음, 명시하지 않아도 컴파일러가 만들어줌
    {
        cout << "Destructor : " << _num << endl;
    }
};

Player player0(0); // 전역 객체, 프로그램 시작 시 생성되고 종료 시 소멸됨
Player* player1 = new Player(1); // 동적 할당된 객체, 명시적으로 해제되지 않으면 메모리 누수 발생

void func()
{
    static Player player2(2); // static 객체, 프로그램이 종료될 때까지 소멸되지 않음
}

void player()
{
    // 생성과 삭제를 확인해보자
    Player player3(3); // 자동 변수, 스코프를 벗어날 때 자동으로 소멸
    Player* player4 = new Player(4); // 동적 할당, delete를 통해 명시적으로 해제 필요
    {
        Player player5(5); // 스코프 내에서 생성되고 스코프가 끝날 때 소멸
        Player* player6 = new Player(6); // 동적 할당, 스코프를 벗어나면 메모리 누수 발생 (delete 필요)
    } // player5는 여기서 소멸, player6는 소멸되지 않음 (delete 필요)
    delete player4; // player4가 가리키는 동적 메모리를 해제
    func(); // static 객체 player2가 생성
    func(); // static 객체는 이미 생성되어 있으므로 새로 생성되지 않음
}

분석:

  • Player 클래스: Player 클래스는 정수형 멤버 변수 _num을 가지고 있으며, 생성자와 소멸자를 정의하고 있습니다. 생성자는 객체가 생성될 때 _num을 초기화하며, 소멸자는 객체가 소멸될 때 _num의 값을 출력합니다.
  • 전역 객체와 동적 할당:
    • Player player0(0);는 전역 객체로, 프로그램이 시작될 때 생성되고 프로그램이 종료될 때 소멸됩니다.
    • Player* player1 = new Player(1);는 동적으로 할당된 객체로, 명시적으로 delete 하지 않으면 프로그램이 종료되어도 메모리에서 해제되지 않아 메모리 누수가 발생합니다.
  • 자동 변수와 스코프:
    • Player player3(3);와 같은 자동 변수는 스코프를 벗어날 때 자동으로 소멸됩니다.
    • Player* player4 = new Player(4);는 동적으로 할당된 객체로, 반드시 delete를 사용하여 메모리를 해제해야 합니다.
    • Player player5(5);는 블록 내에서 생성되고, 블록이 끝나면 자동으로 소멸됩니다.
    • Player* player6 = new Player(6);는 블록이 끝나도 소멸되지 않고 메모리 누수가 발생합니다.
  • Static 객체:
    • func() 함수에서 static Player player2(2);는 프로그램이 종료될 때까지 소멸되지 않습니다. 이 함수가 여러 번 호출되더라도 객체는 한 번만 생성됩니다.

String.h - 동적 메모리 관리

#pragma once
#pragma warning(disable:4996)

#include <iostream>
#include <cstring>

using namespace std;

class String
{
private:
    char* _str;

public:
    String(const char* str)
    {
        int len = strlen(str);
        _str = new char[len + 1]; // '\0' 포함한 길이만큼 메모리 할당
        strcpy(_str, str); // 문자열 복사
    }

    ~String()
    {
        delete[] _str; // 소멸자에서 동적으로 할당된 메모리 해제
    }

    void print()
    {
        cout << _str << endl;
    }
};

void stringFunc()
{
    String str("abc");
    str.print();
}

분석:

  • String 클래스: String 클래스는 동적으로 할당된 문자열을 관리하는 간단한 클래스입니다.
  • 동적 메모리 할당:
    • String(const char* str) 생성자는 입력된 문자열의 길이를 계산하여 _str 멤버 변수에 동적으로 메모리를 할당하고, 문자열을 복사합니다.
    • 동적으로 할당된 메모리는 반드시 나중에 해제되어야 메모리 누수가 발생하지 않으며, 이는 소멸자에서 처리됩니다.
  • 메모리 해제:
    • ~String() 소멸자는 _str에 할당된 메모리를 해제하여 메모리 누수를 방지합니다.
    • delete[] _str;는 배열로 할당된 메모리를 해제하는 데 사용됩니다.
  • stringFunc 함수:
    • String str("abc");String 객체를 자동 변수로 생성합니다. 이 객체는 함수가 종료될 때 자동으로 소멸되며, 이 과정에서 소멸자가 호출되어 동적으로 할당된 메모리가 해제됩니다.

main.cpp - 전체 실행

#include <iostream>
#include "Player.h"
#include "String.h"

using namespace std;

int main()
{
    player();
    stringFunc();
}

분석:

  • main 함수player()stringFunc() 함수를 호출하여 각각 Player 클래스와 String 클래스의 동작을 테스트합니다.
  • player() 함수: 다양한 Player 객체의 생성과 소멸 과정을 통해 자동 변수와 동적 메모리 관리의 차이를 보여줍니다.
  • stringFunc() 함수: 동적으로 할당된 문자열 메모리를 관리하는 String 클래스의 동작을 테스트합니다.

결론

이 코드 예제는 C++에서 소멸자의 중요성과 메모리 관리의 필요성을 잘 설명하고 있습니다. 소멸자는 객체가 소멸될 때 호출되며, 동적으로 할당된 리소스를 해제하는 데 사용됩니다. 이를 통해 메모리 누수(memory leak)를 방지할 수 있습니다. 또한, static 객체전역 객체의 수명과 소멸 시점에 대해 이해할 수 있습니다. 이 예제에서 Player 클래스와 String 클래스의 동작을 통해 메모리 관리의 기본 원칙을 익히고, 이를 실습할 수 있습니다.
\

profile
李家네_공부방

0개의 댓글