CS/개념

Call by Value / Call by Sharing / Call by Reference

tae-woong 2025. 10. 20. 17:03

함수에 인자를 전달할 때, 값을 통째로 복사할 것인지(Call by Value), 객체를 가리키는 주소 값만 복사할 것인지(Call by Sharing), 아니면 원본 변수의 별명을 넘길 것인지(Call by Reference)에 대한 방식의 차이입니다.

 

Call by Value (값에 의한 호출)
  • 개념 : 함수에 인자를 전달할 때, 변수가 가진 값을 그대로 복사하여 전달하는 방식입니다.
  • 동작 : 함수 내부에서 사용되는 매개변수는 원본 변수와는 완전히 독립된 메모리 공간(스택에 새로 생성)을 가집니다.
  • 특징 :
    • 장점 (안정성) : 함수 내에서 매개변수의 값을 변경해도, 원본 변수의 값은 절대 변하지 않습니다. (Side Effect 없음)
    • 단점 (성능) : 만약 전달하는 데이터가 크기가 매우 큰 struct나 class 객체라면, 이 복사 과정(복사 생성자 호출)에서 성능 저하(오버헤드)가 발생할 수 있습니다.

C++ 예시 코드 :

#include <bits/stdc++.h>
using namespace std;

// a는 main의 val 값을 '복사'해서 받음
void callByValue(int a) 
{
    a = 20; // '복사본' a의 값을 변경
    cout << "함수 안 (a): " << a << endl;
}

int main() 
{
    int val = 10;
    cout << "호출 전 (val): " << val << endl;
    
    callByValue(val);
    
    // 함수 안에서 a가 20으로 바뀌었지만, 원본 val은 영향 없음
    cout << "호출 후 (val): " << val << endl; 
    
    return 0;
}

[실행 결과]

호출 전 (val): 10
함수 안 (a): 20
호출 후 (val): 10

[C# 매칭]

  • C#에서 값 타입(Value Type, int, struct 등)을 인자로 전달하는 방식(void ModifyValue(int a))과 완전히 동일하게 동작합니다.

 

Call by Sharing (공유에 의한 호출)
  • 개념 : 함수에 인자를 전달할 때, 힙(Heap) 메모리에 있는 객체를 가리키는 '참조(주소)' 값복사하여 전달하는 방식입니다. (C#, Java의 기본 객체 전달 방식)
  • 동작 : 함수 내의 매개변수(복사된 주소)와 원본 변수(원본 주소)는 서로 다른 변수이지만, 동일한 힙(Heap) 객체를 가리킵니다.
  • C++ 매칭 : C++에서는 포인터(*)를 값으로 전달하는 것(void func(Student* p))과 가장 유사합니다.
  • 특징 :
    • 장점 (효율성) : 큰 객체 자체를 복사하지 않고 주소 값만 복사하므로 오버헤드가 적습니다.
    • 장점 (내용 수정) : 원본 객체의 내용(속성)을 수정할 수 있습니다. (Side Effect 발생)
    • 단점 (원본 교체 불가) : 함수 내에서 매개변수에 새 객체를 할당해도(p = new ...), '복사된 주소'가 바뀔 뿐 '원본 변수'가 가리키는 대상은 바뀌지 않습니다.

C++ 예시 코드 (포인터 전달) :

#include <bits/stdc++.h>
using namespace std;

struct Student { int id; };

// pStu는 main의 s1_ptr이 가진 '주소 값'을 '복사'해서 받음
void callBySharing(Student* pStu) 
{
    // 1. 내용 변경 (O) - 원본 s1의 id가 바뀜
    pStu->id = 20; 

    // 2. 객체 교체 (X)
    // pStu = new Student{30}; // '복사본' pStu가 새 객체를 가리킴
                               // main의 s1_ptr은 여전히 s1을 가리킴
}

int main() 
{
    Student s1 = {10};
    Student* s1_ptr = &s1; // s1_ptr은 s1의 주소를 가짐

    cout << "호출 전 (s1.id): " << s1_ptr->id << endl;
    
    callBySharing(s1_ptr); // '주소 값'을 복사
    
    // 1. 내용 변경은 원본에 적용됨
    cout << "호출 후 (s1.id): " << s1_ptr->id << endl; 
    
    return 0;
}

[실행 결과]

호출 전 (s1.id): 10
호출 후 (s1.id): 20

[C# 매칭]

  • C#에서 ref 키워드 없이 참조 타입(Reference Type, class, 배열 등)을 전달하는 방식(void Func(Student s))과 완전히 동일한 원리입니다.

 

Call by Reference (참조에 의한 호출)
  • 개념 : 함수에 인자를 전달할 때, 값의 복사본이 아닌 원본 변수 자체의 '별명(Alias)'을 전달하는 방식입니다.
  • 동작 : 함수 내의 매개변수는 원본 변수와 동일한 메모리를 가리키는 '별명'이 됩니다.
  • C++ 매칭 : C++에서는 참조자(&)를 사용하는 것이 가장 순수한 형태의 Call by Reference입니다.
  • 특징:
    • 장점 (효율성) : 큰 객체를 전달해도 복사 오버헤드가 없습니다.
    • 장점 (원본 수정) : 함수가 원본 데이터를 직접 수정해야 할 때 사용합니다.
    • 장점 (원본 교체) : 원본 변수 자체를 다른 객체로 교체하는 것도 가능합니다.
    • 단점 (위험성) : 의도치 않은 원본 데이터 훼손(Side Effect)이 발생할 수 있습니다.

C++ 예시 코드 (참조자 & 사용) :

#include <bits/stdc++.h>
using namespace std;

// a는 main의 ref 변수의 '참조(별명)'가 됨
// & 키워드 사용
void callByReference(int& a)
{
    a = 20; // '원본' a(즉, main의 ref)의 값을 변경
    cout << "함수 안 (a): " << a << endl;
}

int main() 
{
    int ref = 10;
    cout << "호출 전 (ref): " << ref << endl;
    
    callByReference(ref);
    
    // 함수 안에서 a가 20으로 바뀌면서, 원본 ref도 함께 변경됨
    cout << "호출 후 (ref): " << ref << endl; 
    
    return 0;
}

[실행 결과]

호출 전: 10
함수 안: 20
호출 후: 20

[C# 매칭]

  • C++의 참조자(&)를 사용한 Call by Reference는 C#의 ref 키워드를 사용한 방식(void ModifyValue(ref int a))과 거의 동일합니다. C#의 ref는 원본 변수의 '별명'을 전달하여 원본을 직접 수정할 수 있게 합니다.

 

3가지 방식 비교표
구분 Call by Value  Call by Sharing Call by Reference
전달 대상 변수의 실제 값 (복사본) 객체를 가리키는 주소 값 (복사본) 원본 변수 자체의 별명(Alias)
원본 값 수정 불가능 (X) (객체 주소 다름. 해당 없음) 가능 (O)
객체 내용 수정 (객체 내용 없음. 단순 값.) 가능 (O) 가능 (O)
원본 변수 교체  불가능 (X) 불가능 (X) 가능 (O)
C++ 구현 void func(int a)
void func(Student s)
void func(Student* p) void func(int& a)
void func(Student& s)
void func(Student*& p)
C# 구현 void func(int a)
void func(MyStruct s)
void func(ClassStudent s) void func(ref int a)
void func(ref Student s)

 

'CS > 개념' 카테고리의 다른 글

오버로딩(Overloading)과 오버라이딩(Overriding)  (0) 2025.10.08
OOP (Object-Oriented Programming)  (0) 2025.10.07