✅ 주제

  • C++에서 함수 인자로 구조체 또는 객체를 전달할 때 사용하는 세 가지 방식(값 복사, 포인터, 참조)을 비교하고, 각각의 장단점, 메모리 영향, 안정성, const 참조의 의미, OUT 매크로의 관용적 표현까지 심층적으로 이해하는 실습 중심 강의

이 강의는 함수 호출 시 어떤 방식으로 데이터를 넘기는 것이 효율적인지 판단하고, 참조와 포인터의 내부 구조를 이해하며 안정성과 성능 사이의 균형을 잡는 법을 학습합니다.


📘 개념

1. 값 전달 방식 (Call by Value)

  • 데이터 전체를 복사해서 함수에 전달
  • 함수 내부에서 값이 변경되더라도 원본에 영향 없음
  • 구조체 크기가 크면 복사 비용이 커짐 → 비효율적

2. 포인터 전달 방식 (Call by Pointer)

  • 주소를 전달하여 함수 내부에서 원본 데이터를 직접 조작
  • 복사 비용 없이 성능에 유리
  • nullptr 체크 필요 – 체크하지 않으면 프로그램 크래시 가능

3. 참조 전달 방식 (Call by Reference)

  • 복사하지 않고 원본을 참조하는 방식
  • 문법적으로 일반 변수처럼 사용
  • null 개념이 없기 때문에 안정성↑
  • 내부적으로는 포인터처럼 작동하지만, 문법은 간결하고 직관적

📗 용어 정리

용어설명
값 전달데이터를 복사해서 함수에 전달
포인터메모리 주소를 저장하는 변수 (* 연산자 사용)
참조기존 변수의 별칭(alias) – 복사 없이 원본 접근
nullptr어떤 것도 가리키지 않는 포인터의 상태
const 참조읽기 전용 참조 – 수정 불가
OUT 매크로함수 인자가 출력(변경) 목적인 것을 명시하는 관용적 매크로

🧩 코드 분석


🔹 구조체 선언 및 초기화

struct StatInfo {
    int hp;
    int attack;
    int defence;
};

StatInfo player = { 100, 10, 1 };
  • player.hp = 100;, player.attack = 10;, player.defence = 1;의 축약 형태
  • 게임 캐릭터의 상태 정보를 담는 구조체

🔹 1. 값 복사 방식

void PrintByCopy(StatInfo player) {
    cout << "-------------------" << endl;
    cout << "HP : " << player.hp << endl;
    cout << "ATT : " << player.attack << endl;
    cout << "DEF : " << player.defence << endl;
    cout << "-------------------" << endl;
}
  • StatInfo player원본이 아닌 복사본
  • 함수 안에서 player를 변경해도 main의 player에는 영향 없음
  • 구조체 크기가 크면 복사 비용 발생

🔹 2. 포인터 전달 방식

void PrintByPointer(StatInfo* player) {
    cout << "-------------------" << endl;
    cout << "HP : " << player->hp << endl;
    cout << "ATT : " << player->attack << endl;
    cout << "DEF : " << player->defence << endl;
    cout << "-------------------" << endl;
}
  • &player를 통해 주소 전달
  • -> 연산자는 포인터가 가리키는 구조체의 멤버 접근을 의미 ((*player).hp와 동일)
  • 원본을 수정할 수 있는 방식
  • 주의: nullptr 전달 시 접근하면 크래시 발생 → 체크 필요

🔹 3. 참조 전달 방식

void PrintByRef(StatInfo& player) {
    cout << "-------------------" << endl;
    cout << "HP : " << player.hp << endl;
    cout << "ATT : " << player.attack << endl;
    cout << "DEF : " << player.defence << endl;
    cout << "-------------------" << endl;
}
  • & 참조 연산자를 통해 복사 없이 원본 전달
  • 함수 안에서는 일반 변수처럼 사용 (.으로 접근)
  • 내부적으로는 포인터와 유사하지만 문법이 직관적
  • null이 될 수 없기 때문에 안정성 뛰어남

🔹 참조와 포인터의 차이

항목포인터참조
NULL 가능 여부가능 (nullptr)불가능 (초기화 필수)
문법*, -> 필요일반 변수처럼 사용 가능
안정성낮음 (null 체크 필요)높음
수정 가능 여부가능가능
초기화 여부나중에 가능선언과 동시에만 가능

🔹 const 참조

void PrintInfo(const StatInfo& player) {
    cout << player.hp << endl;
    // player.hp = 200; // ❌ 수정 불가
}
  • 읽기 전용으로 데이터를 전달
  • 복사 비용 없이 안전하게 사용
  • 읽기 전용 출력 함수 등에 적합

🔹 OUT 매크로

#define OUT

void SetStat(OUT StatInfo& player) {
    player.hp = 50;
}
  • OUT은 컴파일 시 사라지는 주석용 매크로
  • 함수가 출력용 인자를 수정한다는 의도를 코드로 명시
  • 협업 시 코드 가독성 향상

🎯 핵심 요약

전달 방식복사 여부원본 수정 가능안정성메모리 효율
값 복사OXOX
포인터XOXO
참조XOOO
const 참조XXOO
OUT 참조XOOO

profile
李家네_공부방

0개의 댓글