Programming Tools/C++

[C++] 함수의 값, 참조, 주소 반환 (Returning values by value, reference and address)

LiDARian 2021. 6. 14. 18:10
반응형

값의 반환 Return by value

복사본이 호출자에게 반환된다. 리터럴, 변수, 표현식을 반환할 수 있다.

범위 지정 문제를 걱정할 필요가 없다. 함수가 반환되기 전에 지역 변수가 평가되고, 값의 복사본이 호출자에게 반환된다.

 

 

값으로 반환을 사용해야 하는 경우:

함수 내에서 선언된 (지역)변수를 반환할 때
값으로 전달된 매개 변수를 반환할 때

 

아래 예제를 통해서 복사본이 전달됨을 확인해보자.

#include <iostream>
using namespace std;

int doubleValue(int x){
	int value = x * 2;
	
	cout << &value << endl;
	return value; // value의 copy가 반환된다.
}

int main(void)
{
	int x = 2;
	int *y = new int;
	
	*y = doubleValue(x);
	cout << y << endl;
	
	return 0;
}
출력 :
0x7ffe650df5a4
0x7ffe650df5c0

 

보다시피 서로 다른 메모리를 사용하는 것을 알 수 있다. 즉 doubleValue의 value 변수를 그대로 반환하는 것이 아니라 복사본을 반환하는 것이다.

 


주소 반환 Return by address

주소로 반환을 사용해야 하는 경우:

동적 할당된 메모리를 반환할 때
주소로 전달된 매개 변수를 반환할 때
#include <iostream>
using namespace std;

int *doubleValue(int x){
    int value = x * 2;

    cout << &value << endl;
    cout << value << endl;
    return &value;
}

int main(void)
{
    int x = 2;
    int* y = new int;

    y = doubleValue(x);
    cout << y << endl;
    cout << *y << endl;

    return 0;
}

 

출력 :
0x7ffe9cff1f84
4
0
세그멘테이션 오류 (core dumped)

 

이런 출력이 나온다.
반환 직후 value가 소멸한다. 최종적으로 할당되지 않은 메모리(dangling pointer)이기 때문에, 호출자가 이 주소에 접근하면 세그멘테이션 폴트가 발생한다.

따라서 반환하는 주소가 유효한 변수가 되도록 전역변수로 선언하거나, 아예 동적메모리를 할당해주는 것이 좋다.

#include <iostream>
using namespace std;

int* allocateArray(int size)
{
    return new int[size]; // 동적할당 받은 메모리이기에, 함수가 종료된다고 소멸하지 않는다.
}

int main()
{
    int* array = allocateArray(25);

    delete[] array;
    return 0;
}

이런 식으로 말이다.


참조 반환 Return by reference

 

참조로 반환을 사용해야 하는 경우:
참조 매개 변수를 반환할 때함수에 전달된 배열의 요소를 반환할 때함수의 끝에서 소멸하지 않는 구조체나 클래스를 반환할 때(전역 변수로 선언된 구조체/클래스 등)

 

참조로 함수 지역 변수를 반환하면 안 된다.

#include <iostream>
using namespace std;

int& doubleValue(int x) {
    int value = x * 2;

    cout << &value << endl;
    return value; 
} 

int main(void)
{
    int x = 2;
    int y = doubleValue(x);

    return 0;
}
출력 :
세그멘테이션 오류 (core dumped)

 

이미 없어진 지역변수를 참조 받는 것은, 호출자가 쓰레기에 대한 참조를 받는다는 것을 의미한다.
그러므로 컴파일에러 혹은 세그멘테이션 폴트가 결과로 배출된다.

 

아래와 같이 참조를 매개변수로 전달받는 경우, 참조로 반환값을 전달하기에 매우 좋다.

#include <array>
#include <iostream>

int& getElement(std::array<int, 25>& array, int index)
{    
    // array가 참조 그대로 전달되고, 그 참조가 그대로 반환된다.
    return array[index];
}

int main()
{
    std::array<int, 25> array;

    // array의 10번 인덱스에 5를 넣는다.
    getElement(array, 10) = 5;

    std::cout << array[10] << '\n';

    return 0;
}

 

반응형