본문 바로가기

개발공부/C++

다양한 반환 값들

#include <iosteam>

using namespace std;

int getValue(int x)
{
    int value = x * 2;
    //이 함수에서만 유효한 value가 선언이 되고 3 * 2를 연산하여 복사하여 대입된다.
    
    return value;
}

int main()
{
    int value = getValue(3);
    //value가 선언이 되고 해당 함수의 리턴값이 복사하여 대입된다.
    return 0;
}

안전하지만 복사와 변수의 생성등이 여러번 일어난다. 

#include <iostream>

using namespace std;

int* getValue(int x)
{
    int value = x * 2;
    
    return &value;
}

int main()
{
    int value = *getValue(3);
    
    return 0;
}

반환형으로 값의 주소를 반환한다. 그 함수의 리턴값에 디레퍼런싱(dereferencing)한다. 

당장 값(리터럴)을 다른 변수에 넣어서 쓰고자하면 쓸 수는 있지만

이 방법은 함수내에서 쓰이고 없어지는 value의 주소를 참조하는 것이기 때문에 좋은 방법은 아니다.

 

그리고 더 위험한 경우를 보자.

#include <iosteam>

using namespace std;

int* getValue(int x)
{
    int value = x * 2;
    
    return &value;
}

int main()
{
    int *value = getValue(3);
    
    return 0;
}

 

같은 함수이지만 차이점은 main함수 내에 있다. 해당 주소에 있는 값을 바로 디레퍼런싱하는 것이 아닌

변수에 그 주소를 담았다. 이를 사용하기 위해서 담는다면 운영체제가 메모리를 어떻게 쓸 지 모르기에

프로그래머입장에서는 위험한 변수일 수 있다.

#include <iostream>

int* allocateMemory(int size)
{
    return new int[size];
}

int main()
{
    int *array = allocateMemory(1024);
    delete[] array;
    //메모리할당은 함수에서 받고 함수 밖에서 메모리를 반납하고 있다.
    return 0;
}

일반적으로는 할당과 반납이 다른 곳에서 이루어지므로 프로그래머입장에서는 힘들 수 있다.

#include <iostream>

using namespace std;

int& getValue(int x)
{
    int value = x * 2;
    return value;
}

int main()
{
    int &value = getValue(5);
    
    cout << value << endl;
    cout << value << endl;
    
    return 0;
}
10
3609371

 함수의 반환값을 그대로 참조하고 있다. 출력문과 같이 10을 가지고 있다.

함수에서 반환된 뒤 쓰레기값이 들어간 상황이다.

#include <iostream>

using namespace std;

int& getValue(int x)
{
    int value = x * 2;
    return value;
}

int main()
{
    int value = getValue(5);
    
    cout << value << endl;
    cout << value << endl;
    return 0;
}
10
10

main 함수내의 value로 가져와서 출력하므로 비교적 안전하지만 이것 역시 좋은 방법은 아니다.

그렇다고 reference가 전혀 쓸 모가 없는 것은 아니다.

#include <iostream>
#include <array>

using namespace std;

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;
    cout << my_array[30] << endl;

    return 0;
}
1024

이렇게 안전한 영역(메모리)에서 선언을 하고 그 값을 수정하는 함수는 따로 쓰는 경우가 많다.

위 코드에서는 배열의 인덱스의 참조를 반환하는 함수를 정의하여 해당 인덱스의 접근경로를 반환받아 사용한다.

 

이제 여러개의 자료형을 반환해보자.

그래픽스를 하다보면 C.style로 코딩해야할 수도 있는데 그럴때는 구조체를 많이 사용한다.

#include <iostream>

using namespace std;

struct S
{
    int a, b, c, d;
};

S getStruct()
{
    S my_s{ 1, 2, 3, 4 };

    return my_s;
}

int main()
{
    S my_s = getStruct();

    cout << my_s.a << endl;

    return 0;
}

또는 tuple을 사용할 수 있다.

#include <iostream>
#include <array>
#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
    cout << std::get<1>(my_tp) << endl; //b
}

튜플로 감싸서 반환하게 할 수도 있다.

c++17에서는 auto키워드로 자료형을 몰라도 크기에 맞추어 받게끔 할 수 있다.

'개발공부 > C++' 카테고리의 다른 글

키워드 : friend  (0) 2019.10.23
정적 멤버  (0) 2019.10.23
다중포인터와 동적 다차원 배열  (0) 2019.10.22
포인터와 참조의 멤버 선택  (0) 2019.10.22
참조변수 reference variable  (0) 2019.10.22