포인터와 메모리

C와 C++에서 const 올바르게 쓰기

이 레슨에서는 const 키워드로 읽기 전용 데이터를 선언하고, const와 포인터를 조합하는 여러 방법을 구분합니다.

소개

const 키워드를 쓰면 함수가 받은 데이터를 바꾸지 않겠다고 약속할 수 있습니다. const로 표시한 데이터를 누군가 실수로 바꾸면 컴파일러가 즉시 오류를 알립니다. 그래서 코드가 더 안전해지고, 읽는 사람도 어떤 함수가 데이터를 바꿀 수 있는지 쉽게 알 수 있습니다.

핵심 정리

  • 포인터는 아직 존재하는 올바른 타입의 객체만 가리키거나 null이어야 합니다.
  • 할당한 메모리 영역은 정확히 한 번만 해제해야 합니다.
  • 어떤 함수가 메모리를 소유(ownership)하는지, 어떤 데이터는 읽기만 하는지(const) 분명히 하세요.

C와 C++ 코드 예제

C
실행 →
main.c
#include <stdio.h>

int sum(const int *values, size_t count) {
    int total = 0;
    for (size_t i = 0; i < count; ++i) total += values[i];
    return total;
}

int main(void) {
    const int values[] = {2, 4, 6};
    printf("%d\n", sum(values, 3));
    return 0;
}
실행 결과
12
C++
실행 →
main.cpp
#include <array>
#include <iostream>

int sum(const std::array<int, 3>& values) {
    int total = 0;
    for (int value : values) total += value;
    return total;
}

int main() {
    const std::array values{2, 4, 6};
    std::cout << sum(values) << '\n';
}
실행 결과
12

C와 C++ 비교

매개변수 const int *values는 sum 함수가 배열 요소를 읽기만 하고 바꾸지 않는다는 뜻입니다. 선언은 변수 이름에서부터 읽으세요. const 데이터를 가리키는 포인터(const int *)는 가리키는 값을 보호하고, const 포인터(int * const)는 다른 주소를 가리킬 수 없습니다. C++에는 객체의 상태를 바꾸지 않겠다고 약속하는 const 멤버 함수도 있습니다.

C

메모리의 소유와 해제는 전적으로 프로그래머에게 달려 있습니다.

C++

컨테이너와 RAII가 객체의 수명이 끝날 때 자원을 자동으로 해제합니다.

연습 문제

두 버전을 모두 실행한 다음 코드를 바꿔 보면서 각 언어가 주는 안전성의 차이를 살펴보세요.

  • 널 포인터와 메모리 할당 실패 상황으로 테스트해 보세요.
  • AddressSanitizer와 UndefinedBehaviorSanitizer로 실행해 메모리 오류를 찾아보세요.
  • 어떤 포인터가 메모리를 소유하고 어떤 포인터는 읽기만 하는지 분명히 해 보세요.