Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 값 전달(Call by Value) vs 참조 전달(Call by Reference), 무엇이 더 나을까?

C++에서는 함수에 인수를 전달하는 여러 가지 방법이 있습니다. 대표적인 방식은 다음과 같습니다.

  • 값에 의한 호출(Call by Value)
  • 참조에 의한 호출(Call by Reference)
  • 주소에 의한 호출(Call by Address)

때때로 '주소에 의한 호출'이 '참조에 의한 호출'과 같은 개념으로 알려져 있지만, C++에서는 두 방식이 서로 다릅니다. 주소에 의한 호출에서는 포인터 변수를 사용해 변수의 실제 메모리 주소를 전달하지만, 참조에 의한 호출에서는 해당 변수의 별칭(alias)인 참조 변수를 전달합니다. 이러한 참조 기능은 C 언어에는 없으며, C에서는 포인터를 전달해야만 비슷한 효과를 얻을 수 있습니다.

이 글에서는 참조에 의한 호출이 값에 의한 호출보다 어떤 점에서 유리한지, 그리고 각각을 언제 사용해야 하는지 살펴보겠습니다.

값에 의한 호출(Call by Value)

값에 의한 호출에서는 함수 내부에서 아무리 연산을 수행해도 원본 인수의 값은 변경되지 않습니다. 값에 의한 호출을 사용하면 메모리의 스택 영역에 해당 변수의 복사본이 생성됩니다. 함수 안에서 값을 변경하면 그 복사본의 값만 바뀌며, 실제 원본 값은 그대로 유지됩니다.

예제 코드

#include<iostream>

using namespace std;

void my_function(int x) {
    x = 50;
    cout << "Value of x from my_function: " << x << endl;
}

main() {
    int x = 10;
    my_function(x);
    cout << "Value of x from main function: " << x;
}

실행 결과

Value of x from my_function: 50
Value of x from main function: 10

참조에 의한 호출(Call by Reference)

참조에 의한 호출에서는 함수 내부에서 수행한 연산이 실제 인수의 값에 그대로 반영됩니다. 참조에 의한 호출을 사용하면 스택 영역에 변수 자체가 아니라 변수에 대한 참조(별칭)가 저장되며, 함수는 이 참조를 통해 원본 값에 접근합니다. 따라서 참조를 통해 값을 변경하면 실제 변수의 값도 함께 변경됩니다.

예제 코드

#include<iostream>
using namespace std;

void my_function(int &x) {
    x = 50;
    cout << "Value of x from my_function: " << x << endl;
}

main() {
    int x = 10;
    my_function(x);
    cout << "Value of x from main function: " << x;
}

실행 결과

Value of x from my_function: 50
Value of x from main function: 50

참조에 의한 호출은 언제 사용할까?

  • 호출자(caller) 쪽으로 전달된 인수의 값을 함수 내부에서 직접 변경하고 싶을 때 주로 사용합니다.

  • 함수는 원칙적으로 하나의 반환값만 돌려줄 수 있습니다. 하지만 두 개 이상의 결과값이 필요할 때는 출력용 인수(output argument)를 참조로 전달하는 방식으로 여러 값을 받아올 수 있습니다.

정리: 어느 쪽을 선택해야 할까?

원본 데이터를 보호하고 싶다면 값에 의한 호출이 적합합니다. 특히 int, double처럼 크기가 작은 기본 타입은 복사 비용이 거의 없기 때문에 값 전달이 안전하고 효율적입니다.

반면, 함수가 원본 값을 수정해야 하거나 문자열, 컨테이너처럼 크기가 큰 객체를 다룰 때는 불필요한 복사를 피하기 위해 참조 전달이 유리합니다. 이때 원본 수정을 막고 싶다면 const 참조(const T&)를 사용하는 것이 C++의 일반적인 관례입니다.