1.8 전달 방식

SeungHee Yun·2023년 9월 5일
0

전문가를 위한 C++

목록 보기
8/15

개요

C++에서는 크게 값으로 전달 / 참조로 전달 하는 두 가지의 전달 방식이 있습니다.
각 전달 방식 모두 장단점과 사용해야 하는 경우,
사용하지 않아야 하는 경우가 있습니다.


값으로 전달 ( Pass by Value )

C++에서 포인터가 아닌 인수는 값으로 전달 됩니다.
인수가 값으로 전달되면, 인수의 값은 해당 함수 매개 변수의 값으로 복사됩니다.

    void foo(int y)
    {
        cout << "y = " << y << endl;
    }

    int main()
    {
        foo(5);     // first call

        int x  = 6;
        foo(x);     // second call
        foo(x+1);   // third call

        return 0;
    }

첫 번재 foo(5) 호출에서 인수는 리터럴 5입니다.
foo(5)가 호출되면 변수 y가 만들어지고
값 5가 y로 복사됩니다. 변수 y는 foo() 함수가 종료되면 소멸합니다.
두 번째, 세 번째 call 도 마찬가지입니다.

즉, 인수의 복사본이 함수로 전달되므로 원래 인수는 함수 안에서 수정할 수 없습니다.

#include <iostream>

void foo(int y)
{
	std::cout << "y = " << y << '\n';

	y = 6;

	std::cout << "y = " << y << '\n';
} // y is destroyed here

int main()
{
	int x = 5;
	std::cout << "x = " << x << '\n';

	foo(x);

	std::cout << "x = " << x << '\n';
	return 0;
}

x = 5
y = 5
y = 6
x = 5

main 함수의 시작 부분에서 변수 x의 값은 5입니다.
foo(X)가 호출되면 foo의 매개변수 y에 값 5가 복사되어 전달됩니다.

foo() 함수 내부에서 y의 값은 6으로 변경되고 소멸하지만,
y가 변경되더라도 변수 x의 값은 아무런 영향을 받지 않습니다.


값으로 전달의 장단점

값으로 전달의 장점

  • 호출되는 함수에 의해 인수가 변경되지 않으므로
    예기치 못한 부작용이 발생하지 않는다.

값으로 전달의 단점

  • 함수를 여러 번 호출하는 경우, 구조체(struct) 및 클래스(class)를 복사하는데
    큰 비용이 들어 성능이 저하될 수 있다.

값으로 전달을 사용해야 하는 경우

  • 기본 자료형과 열거자를 전달할 때(함수가 인수를 변경할 필요가 없을 때)

값으로 전달을 사용하지 않아야 하는 경우

  • 배열(array), 구조체(struct), 및 클래스(class) 를 전달할 때

주소로 전달 ( Pass by address )

값으로 전달은 두 가지 한계가 있습니다.

  • 큰 구조체 또는 클래스를 함수에 전달할 때 값으로 전달은
    인수의 복사본을 함수 매개 변수로 만든다.
    이 경우, 복사하는데 큰 비용이 들어 성능이 저하될 수 있다.
  • 값으로 인수를 전달할 경우, 함수에서 호출자에게 값을 반환하는
    유일한 방법은 함수의 반환 값을 사용하는 것이다.
    이 방법도 좋지만, 함수에서 인수를 수정하는 것이 더 명확하고 효율적일 수 있다.

변수를 참조로 전달하려면,
함수 매개 변수를 일반 변수가 아닌 참조로 선언해야 합니다.

    void addOne(int& y)
    {
        y = y+1;
    }

함수가 호출되면 y는 인수에 대한 참조가 됩니다.

변수에 대한 참조는 변수 자체와 똑같이 취급되므로
참조에 대한 모든 변경 사항은 인수에도 적용됩니다.

void foo(int& value)
{
	value = 6;
}

int main()
{
	int value = 5;

	cout << "value = " << value << '\n';
	foo(value);
	cout << "value = " << value << '\n';
	return 0;
}

value = 5
value = 6

보다시피 함수는 인수의 값을 5에서 6으로 변경했습니다.


const 참조로 전달 ( Pass by const Reference )

참조를 사용하면 함수가 인수의 값을 변경할 수 있으므로 인수가 읽기 전용일 때는
사용하기에 바람직하지 않습니다. 함수가 인수의 값을 변경해서는 안되지만 값으로
전달하지 않으려면 const 참조를 전달하는 것이 가장 좋습니다.

const 참조는 변수가 참조를 통해 변경되는 것을 허용하지 않는 참조입니다.
그러므로 const 참조를 매개변수로 사용하면
함수가 인수를 변경하지 않는다는 것을 호출자에게 보장합니다.

const 참조를 사용하는 것은 다음과 같은 이유로 유용합니다.

  • 컴파일러는 변경해서 안되는 값을 변경하지 않도록 합니다.

  • 함수가 인수의 값을 변경하지 않는다는 것을 프로그래머에게 알려줍니다.

  • const가 아닌 참조 매개 변수에는 const 인수를 전달할 수 없습니다.

  • const 참조는 l-value, const l-value 및 r-value를 포함한 모든 유형의 인수를 허용합니다.


포인터에 대한 참조 ( References to Pointers)

포인터를 참조로 전달하고,
함수가 포인터의 주소를 완전히 변경하도록 할 수 있습니다.

#include <iostream>

void foo(int*& ptr) // pass pointer by reference
{
	ptr = nullptr; // 실제 ptr 인수를 변경할 수 있다.
}

int main()
{
	int x = 5;
	int *ptr = &x;
	std::cout << "ptr is: " << (ptr ? "non-null" : "null") << '\n'; // prints non-null
	foo(ptr);
	std::cout << "ptr is: " << (ptr ? "non-null" : "null") << '\n'; // prints null

	return 0;
}

참조로 전달의 장단점

참조로 전달의 장점

  • 참조를 사용하면 함수가 인수의 값을 변경할 수 있다. 또한, const 참조를 사용해서 함수가 인수를 변경하지 않는다는 것을 보장할 수 있다.
  • 인수의 복사본이 만들어지지 않으므로
    큰 구조체나 클래스와 함께 사용하는 경우에도 전달이 빠르다
  • 참조는 함수에서 매개 변수를 통해 여러 값을 반환할 수 있다.
  • 참조는 초기화되어야 하므로 null 값에 대해 걱정할 필요가 없다.

참조로 전달의 단점

  • non-const 참조는 const 값, 또는 r-value로 초기화할 수 없으므로
    참조 매개변수에 대한 인수는 일반 변수여야 한다.

  • 인수가 변경될 수 있는지는 함수 호출에서 알 수 없다.
    값으로 전달이나 참조로 전달 모두 인수에서는 동일하게 보인다.
    함수 선언을 보고 인수가 값으로 전달인지 참조로 전달인지 알 수 있다.
    이것은 프로그래머가 함수에서 인수의 값을
    변경한다는 것을 인식하지 못하는 상황을 초래할 수 있다.

참조로 전달을 사용해야 하는 경우

  • 구조체 또는 클래스를 전달할 때 (읽기 전용인 경우 const 사용)
  • 인수를 수정하는 함수가 필요할 때
  • 고정 배열의 유형 정보에 접근해야 할 때

참조로 전달을 사용하지 않아야 하는 경우

  • 수정할 필요가 없는 기본 자료형을 전달할 때 (값으로 전달 사용)

참조 : 소년코딩


profile
Enthusiastic Game Developer

0개의 댓글