C++ Chapter 7.3 : 다양한 리턴 값
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
chapter 7. 함수 : 다양한 리턴 값
1. 값을 리턴
int getValue(int x)
{
int value = x * 2;
return value;
}
int main()
{
int value = getValue(3);
return 0;
}
- getValue(3)
- 함수가 호출되고 인수
3
이 넘어가면서int
getValue 함수의 매개변수인int x
에 3이 복사된다.- 내부적으로
int x = 3
과정이 이루어짐 - getValue 함수의 지역변수인
value
(값 6)가 리턴된다.
- 내부적으로
- 함수가 호출되고 인수
- int value = getValue(3);
- getValue의 리턴값인
value
의 값이main의 value
에 복사된다. - 그리고 getValue가 역할을 다하고 끝내면서 지역변수인 value도 메모리에서 사라진다.
- getValue의 리턴값인
int
리턴 +int value = getValue(3);
- 리턴을 이렇게 값으로 하면 대규모로 진행할시 느려질 수 있다.
- 복사가 많아지니까!
- 구조체, 클래스, 배열 사용시에는 비효율적인 방법이다.
- 변수 하나를 리턴하는 경우라면 값을 리턴하는 것이 효율적이고 안전하다.
- 리턴을 이렇게 값으로 하면 대규모로 진행할시 느려질 수 있다.
2. 주소를 리턴
int * allocateMemory(int size)
{
return new int[size];
}
int main()
{
int * array = allocatememory(1024);
delete [] array;
return 0;
}
- allocatememory(1024)
- 함수가 호출되고 인수
1024
가 넘어가면서int *
allocateMemory 함수의 매개변수인int size
에 1024가 복사된다.- 내부적으로
int size = 1024
과정이 이루어짐
- 내부적으로
- 함수가 호출되고 인수
- int * array = allocatememory(1024);
- allocatememory의 리턴값인
new int[size]
의 값이main의 int * array
에 대입된다.new
는 동적 할당 메모리의 주소값을 리턴하므로 주소값이main의 int * array
에 대입된다.new
는 힙메모리에서 동적 할당 받기 때문에 함수 범위가 끝나도 사라지지 않는다. 동적 할당 메모리는 프로그래머가 직접delete
로 반납하기 전까지는 계속 살아있음.
- 함수 호출이 끝나고 리턴이 다 끝나도
new
로 동적 할당 받은 힙 메모리는 유지됨 - 지역 변수인 size만 사라짐
- allocatememory의 리턴값인
int * getValue(int x)
{
int value = x * 2;
return &value;
}
int main()
{
int * value_1 = getValue(3);
int value_2 = *getValue(3);
return 0;
}
return &value;
: 이렇게 주소값 리터럴 (R-value)로 리턴하는 경우
- value는 지역변수이므로 리턴 후 메모리가 해제되고 사라지기 때문에 이미 사라진 곳의 주소를 넘기게 되는 것일 수 있어 위험할 수 있다. 사라진 메모리의 주소를 복사받는 것이니까.
int * value_1 = getValue(3);
- 메모리가 사라진 값의 주소를 받음
int value_2 = *getValue(3);
- 메모리가 사라진 값의 주소를 간접참조함
- 따라서 포인터를 리턴할시 위와 같이 코드를 짜는것은 지양하자.
- int * array = allocatememory(1024); 같은 경우는 동적 할당 받아 사라지지 않는 힙메모리를 사용한 것이니 함수가 끝나면서 사라질 위험이 없기 때문에 안전한 것.
- 이처럼 함수 내에서 선언된 지역변수를 반환하는 경우에는 ***주소 리턴***을 받지 말자. 위험함.
3. 참조를 리턴
그냥 int 로 int & 참조 리턴을 대입 받는 경우
int & getValue(int x)
{
int value = x * 2;
return value; // value의 참조를 리턴
}
int main()
{
int value = getValue(3);
return 0;
}
- getValue(3)
- 함수가 호출되고 인수
3
이 넘어가면서int
getValue 함수의 매개변수인int x
에 3이 복사된다.- 내부적으로
int x = 3
과정이 이루어짐 - getValue 함수의 지역변수인
value
(값 6)가 리턴된다.
- 내부적으로
- 함수가 호출되고 인수
- int value = getValue(3);
main의 value
는int & getValue
에서 리턴한value
가 참조하는 메모리를 복사 받게 된다!int & value
가 아닌그냥 int value
로 함수 리턴값을 대입 받아서 참조가 아닌 그냥 리턴값을 복사한게 되는 것.- 이 함수는 리턴타입이
int &
이 되므로 value에 대한 참조를 리턴한다.
- 그냥 int, 즉 값으로 리턴하면
return value
더라도 value의 값, 즉R-value
로서 리턴을 하게 되는데 - int &, 즉 참조로 리턴하면
L-value
로서 리턴을 하게 된다. - 그러나 getValue가 역할을 다하고 끝내면서 지역변수이자 참조 변수인 value가 참조하는 메모라 공간은 잠깐 있다 사라진다. -main의 value
는 없어진 공간을 복사 받은 셈이 되는 것이다 - 그래서 실행하면 warning: reference to local variable ‘value’ returned [-Wreturn-local-add] 같은 경고메세지가 뜸.
int & 참조 변수로 int & 참조 리턴을 대입 받는 경우
int & getValue(int x)
{
int value = x * 2;
return value; // value의 참조를 리턴
}
int main()
{
int & value = getValue(3);
cout << value << endl; // 6으로 잘 나온다.
cout << value << endl; // 쓰레기 값이 나온다.
return 0;
}
int & value = getValue(3);
- getValue 함수의 지역변수 value의 메모리 공간을 참조 변수
int &
인 value가 참조하게 된다. - 함수가 종료되며 지역 변수인 value 메모리 공간은 파괴된다.
- 그러나 !!
main의 int & 변수인 value
는 계속해서 이 파괴되어 쓰레기 값 들어있는 공간을 참조한다.- 따라서 한번 더 value를 출력하려하면 쓰레기값이 나오는 것. 사라져버려서 ㅠ ㅠ
- 이처럼 함수 내에서 선언된 지역변수를 반환하는 경우에는 ***참조 리턴***을 받지 말자. 위험함. 주소 리턴과 마찬가지로 !
int & get(std::array<int, 100> & my_array, int ix)
{
return my_array[ix];
}
int main()
{
std::array<int, 100> my_array;
my_array[30] = 10;
get(my_array, 30) = 1024; // my_array[30] = 1024 과 동일
}
- 인수를 기존에 main에서 메모리를 잡고 있는 상태인 배열의 참조로 넘긴 상태. std::array<int, 100>
&
my_array- 따라서
get 내의 지역변수 my_array
는 함수가 끝나고 사라져도 공간은 사라지지 않고 계속 존재하기 때문에 기존 공간을 참조 매개변수에게 넘기고 이를 리턴받을 경우엔 위험할 일이 없다.
- 따라서
get(my_array, 30) = 1024;
- 참조로 리턴했기 때문에, 즉 L-value로서 리턴했기 때문에 변수에 값을 저장하는 것 처럼 보인다.
- my_array[30] = 1024 과 동일
- 참조로 리턴했기 때문에, 즉 L-value로서 리턴했기 때문에 변수에 값을 저장하는 것 처럼 보인다.
정리
int 값
리턴 : 임시 변수에 리턴된 객체를 복사한 후 그 임시 변수를 R-value 속성으로 리턴한다.- 즉, 해당 객체가 아닌 주소가 다른 임시 변수의 메모리가 리턴 된다.
int & 참조
리턴 : 임시 변수에 복사하는 과정 없이 그 객체를 레퍼런스, 즉 실제 객체 그 자체를 L-value 속성으로 리턴한다.- 리턴하는게 단순 함수 내의 지역변수라면 소멸 시점을 주의하여야 한다.
- 함수가 소멸되면서 지역변수도 소멸되는데 지역 변수를 참조로 리턴 받은 바깥 변수는 여전히 소멸된 지역변수 메모리 자리를 참조하고 있는 것이 되기 때문이다.
4. 구조체를 리턴
using namespace std;
struct S
{
int a, b, c, d;
};
S getStruct()
{
S my_s{1, 2, 3, 4};
};
int main()
{
S my_s = getStruct();
cout << my_s.b << endl;
return 0;
}
- 구조체를 리턴받아 값을 받을 경우 한번에 여러개의 값을 받을 수 있다.
- 함수를 하나 만들 때마다 구조체 또한 또 만들어야 하는게 단점
튜플(Tuple)
로 극복할 수 있다.
5. 튜플을 리턴
#include <tuple>
using namespace std;
std::tuple<int, double> getTuple()
{
int a = 10;
double d = 3.14;
return std::make_tuple(a, d);
}
int main()
{
std::tuple<int, double> my_tp = getTuple();
cout << std::get<0>(my_tp) << endl; // a. int다
cout << std::get<1>(my_tp) << endl; // b. double이다.
return 0;
}
- #include <tuple>
- std::tuple
- std::make_tuple
- 튜플은 대괄호
[]
를 쓴다. - 튜플을 통해 각각 자료형이 다른 두개 이상의 리턴값을 받을 수 있다.
- C++ 17부턴
std::tuple<int, double> my_tp = getTuple();
을 간단하게auto[a, d] = getTuple
이런식으로 쓸 수 있다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기