메모리 릭을 추적해주는 함수
// Main.cpp
#include <crtdbg.h> // _CrtSetDbgFlag(), _CrtSetBreakAlloc()
class Human
{
public:
float Height;
float Weight;
};
int main(void)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// 메모리 릭 추적.
// _CrtSetBreakAlloc(161);
// 메모리 릭 지점에 자동으로 중단점을 걸어주는 함수.
Human* Park = new Human();
//delete Park;
//Park = nullptr;
return 0;
}
이 코드를 실행한 후 디버그 창을 보면 메모리 릭이 나는 것을 아래와 같이 확인할 수 있다.



생성자
// Main.cpp
#include <iostream>
#include "Human.h"
int main(void)
{
Human Human01 = Human();
// 생성자를 명시적으로 호출해서 객체를 만들고, 그걸 다시 Human01에 대입.
Human* Human02 = new Human();
// 생성자의 명시적 호출.
Human Human03;
// 생성자의 암시적 호출.
Human* Human04;
// Q. 이건 무슨 일이 벌어질까요?
delete Human02;
Human02 = nullptr;
return 0;
}
Human()과 new Human()의 차이점은 스택메모리에 만드냐 힙 메모리에 만드느냐이다.
Human* Human04는 생성자 호출 안 된다.
| Human01 | Stack | ✅ 명시적 | main() 종료 시 자동 |
| Human02 | Heap | ✅ 명시적 | delete 호출 시 |
| Human03 | Stack | ✅ 암시적 | main() 종료 시 자동 |
| Human04 | Stack | ❌ 없음 | 포인터만 존재, 위험! |
스택 메모리는 main 종료 시점에 자동 소멸된다.
멤버변수로 다른 클래스의 객체를 갖고 있는 경우에는?
모든 멤버 변수 객체의 생성자도 호출된다.
순서: 멤버변수 생성자 호출 -> 자기 자신의 생성자 호출
const 변수와 참조 변수는 이니셜라이저 리스트로 초기화해줘야한다.
특정 매개변수를 가진 생성자를 만들면, 기본 생성자는 안 만들어진다.
소멸자
소멸자는 오버로딩 불가.
동적할당 메모리 소유권
// Human.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "Human.h"
#include <iostream>
#include <cstring>
using namespace std;
Human::Human()
: Height(0.0f)
, Weight(0.0f)
, BirthDay(20260101)
, Name(nullptr)
{
cout << "Human() constructor has been called." << endl;
Name = new char[8];
strcpy(Name, "None");
}
Human::Human(float InHeight, float InWeight, int InBirthDay)
: Height(InHeight)
, Weight(InWeight)
, BirthDay(InBirthDay)
, Name(nullptr)
{
cout << "Human(float InHeight, float InWeight, int InBirthDay) constructor has been called." << endl;
Name = new char[8];
strcpy(Name, "None");
}
Human::Human(float InHeight, float InWeight, int InBirthDay, const char* InName)
: BirthDay(InBirthDay)
{
cout << "Human(float InHeight, float InWeight, int InBirthDay, const char* InName) constructor has been called." << endl;
Height = InHeight;
Weight = InWeight;
Name = new char[strlen(InName) + 1];
strcpy(Name, InName);
}
Human::~Human()
{
cout << "~Human() destructor has been called." << endl;
if (Name != nullptr)
{
delete[] Name;
Name = nullptr;
}
}
void Human::PrintInfo()
{
cout << "Height: " << Height << " cm" << endl;
cout << "Weight: " << Weight << " kg" << endl;
cout << "BirthDay: " << BirthDay << endl;
cout << "Name: " << Name << endl;
}
// Main.cpp
#include <crtdbg.h> // _CrtSetDbgFlag(), _CrtSetBreakAlloc()
#include "Human.h"
int main(void)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// 메모리 릭 추적.
Human Kim = Human(182.0f, 75.0f, 19990101, "Kim");
Human Lee(182.0f, 75.0f, 19990101);
Human Park;
Kim.PrintInfo();
Lee.PrintInfo();
Park.PrintInfo();
// Q. 메모리 릭이 날까요? 안난다면 왜 안날까요?
return 0;
}
Name 멤버 변수를 만들어서 동적할당은 했지만, 메모리 릭은 나지 않습니다. 그 이유는 main() 함수 종료 되면서 Kim 지역 변수가 사라지고, 소멸자가 자동으로 호출되게 됩니다. 소멸자에서는 Name 멤버 변수에 동적할당된 메모리 주소를 delete 해주기 때문입니다.
// Main.cpp
#include <crtdbg.h> // _CrtSetDbgFlag(), _CrtSetBreakAlloc()
#include "Human.h"
int main(void)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
Human* Park = new Human(178.0f, 68.0f, 20200202, "Park");
Park->PrintInfo();
// Q. 메모리 릭이 날까요? 난다면 왜 날까요?
return 0;
}
여기에선 메모리 릭이 남.
Human*로 선언한 Park도 delete 해줘야 함.
delete Park;
Park = nullptr;
C언어에서의 malloc() / free() Vs. C++의 new / delete
가장 큰 차이점은 new / delete는 생성자 / 소멸자가 자동으로 호출된다는 점.
[심화] RAII(Resource Acquisition Is Initialization)
C++에서는 객체에게 필요한 자원을 생성자에서 획득하게끔하고, 소멸자에서 획득한 자원을 해제하도록 설계하는 것이 필수적.
자원을 획득한 주체가 자원을 해제한다.
이를 RAII라고 하며, C++ 메모리 관리의 핵심 철학.
friend 키워드
다른 클래스나 다른 함수 내에서 클래스의 private 혹은 protected 멤버에 접근 가능하게 해 줌.
// Human.h
#pragma once
class Human
{
friend class BestFriend;
public:
Human()
: Height(165.0f)
, Weight(52.0f)
{
}
private:
float Height;
float Weight;
};
// BestFriend.h
#pragma once
class Human;
class BestFriend
{
public:
void PrintYourInfo(const Human& InPerson);
};
// BestFriend.cpp
#include "BestFriend.h"
#include <iostream>
#include "Human.h"
void BestFriend::PrintYourInfo(const Human& InPerson)
{
std::cout << "Height: " << InPerson.Height << std::endl;
std::cout << "Weight: " << InPerson.Weight << std::endl;
}
전역 함수에도 선언 가능하다.
// Human.h
#pragma once
class Human
{
friend float GetBMI(const Human& InPerson); // 멤버 함수가 아닌 전역 함수
public:
Human()
: Height(165.0f)
, Weight(52.0f)
{
}
private:
float Height;
float Weight;
};
// Human.cpp
#include "Human.h"
float GetBMI(const Human& InHuman) // 관찰 포인트. 전역 함수라 범위지정자가 안쓰였습니다.
{
return InHuman.Weight / ((InHuman.Height / 100.0f) * (InHuman.Height / 100.0f));
}
friend 지정은 단방향이로, 클래스 상호적용이 되게 하고 싶다면 각각 선언해주어야한다.
'코딩 학습 > C와 C++' 카테고리의 다른 글
| C++ 기초 - Console IO (0) | 2026.04.03 |
|---|---|
| C++ 배치고사 선택 문제 (0) | 2026.04.03 |
| C++ 배치고사 필수 문제 (0) | 2026.04.02 |
| C++ 팀프로젝트 - 텍스트 RPG 게임 만들기(4) (0) | 2026.03.31 |
| C++ 팀프로젝트 - 텍스트 RPG 게임 만들기(2) (0) | 2026.03.27 |