Project Hub

2. reference 본문

C++/c++ basic

2. reference

safy 2022. 12. 21. 11:20
728x90
반응형

이전 글 

2022.12.21 - [C++/c++ basic] - 1. namespace

 

1. namespace

namespace(이름공간) 개체를 구분할 수 있는 범위를 나타내는 말 함수나 구조체 혹은 변수 이름 등의 소속을 정해주는 것 아래는 namespace 사용 예시 중 하나다. 각각의 header1, header2 라는 namespcae 가

projecthub.tistory.com

 

reference

다른 변수나 상수를 가리키는 방법
C 에서는 포인터를 사용

reference의 예시.

#include <iostream>
int ChangeValue(int *p)
{
    *p = 3;
    return 0;
}
 
int main()
{
    int number = 5;
    std::cout << number << std::endl;
 
    // ChangeValue 함수의 인자 p 에 number 의 주소값을 전달.
    // *p를 통해 number 를 참조하여 값은 변환함.
    ChangeValue(&number);
    std::cout << number << std::endl;
     
    return 0;
}

 

reference의 특징

  • reference는 반드시 처음에 누구의 별명이 될 것인지 지정해야 한다. (포인터 선언과 차이점이 있다.)
int* another_a; // 포인터는 이렇게 선언을 해도 문제가 되지 않는다.
int& another_a; // 다음과 같은 변수의 선언은 불가능하다.
 
int a = 10;
int& another_a = a // another_a 는 a의 reference가 된다.

 

  • reference가 한 번 별명이 되면 절대로 다른 이의 별명이 될 수 없다.
int a = 10;
int &another_a = a; // another_a 는 a 의 reference
 
int b = 3;
another_a = b   // another_a 가 변수 b를 가리키는 것이 아니다. a 에 b를 대입하라는 것과 같다. 
		//즉, a = b와 동치인 문장.
 
&another_a = b; // 해당 문장은 말이 되지 않는다. &a = b; 가 되기 때문.
 
// 포인터는 다르다.
int a = 10;
int* p = &a; // p 는 a 를 가리킨다.
 
int b = 3;
p = &b; // 이제 p 는 a 를 버리고 b 를 가리킨다.

 

  • reference는 메모리 상에 존재하지 않을 수 도 있다. 
// 포인터의 경우,
int a = 10;
int* p = &a // p 는 메모리 상에서 8 바이트를 차지하게 된다.(64 bit 환경)
 
// reference의 경우,
int a = 10;
int &another_a = a; // another_a 가 메모리를 차지할 필요가 없다. 
		// another_a 가 쓰이는 자리를 모두 a 로 바꾸면 됨.


상수에 대한 참조자

#include <iostream>
 
int main()
{
    // 아래와 같은 문장은 컴파일 오류가 발생한다. 이유는 상수 값 자체는 리터럴 이기 때문이다.
    // 리터럴: 소스 코드 상에서 고정된 값을 가지는 것
    int &ref = 4;
     
    std::cout << ref << std::endl;
}
 
/////////////////////////////////////////////////////////////
// 아래와 같은 문장은 가능하다.
const int &ref = 4;


레퍼런스의 배열 

아래와 같은 문장은 오류를 반환한다. (illegal)

int a, b;
int& arr[2] = {a, b};


레퍼런스 배열에 대해서는 언어 차원에서 불가능하다고 한다.

레퍼런스의 레퍼런스, 레퍼런스의 배열, 레퍼런스의 포인터는 존재할 수 없다.

이유는 레퍼런스는 특별한 경우가 아닌 이상 메모리 상에서 공간을 차지하지 않기 때문이다.

 

배열의 레퍼런스

아래와 같이 배열의 레퍼런스는 가능하다.

주의할 점은 자료형과 배열의 크기가 동일해야 한다.

#include <iostream>
 
int main()
{
    int arr[3] = {1, 2, 3};
    int(&ref)[3] = arr;
 
    ref[0] = 2;
    ref[0] = 3;
    ref[0] = 1;
 
    std::cout << arr[0] << arr[1] << arr[2] << std::endl;
 
    return 0;
}


레퍼런스를 리턴하는 함수

아래 코드를 보면 function 안에 정의된 a 라는 변수의 값이 b 에 복사되었다.

function 이 종료되면 a 는 메모리에서 사라지게 된다. 

int function()
{
    int a = 2;
    return a;
}
 
int main()
{
    int b = function();
    return 0;
}


아래 코드에서는 function 함수가 레퍼런스를 리턴하게 된다. 

그런데 문제는 a 는 함수의 리턴과 함께 사라지기 때문에 b 가 참조해야 하는 변수가 사라지게 되어 오류가 발생하게 된다.

이와 같이 레퍼런스는 있는데 원래 참조 하던 것이 사라진 레퍼런스를 댕글링 레퍼런스라고 부른다.

int& function()
{
    int a = 2;
    return a;
}
 
int main()
{
    int b = function();
    return 0;
}


아래의 코드는 함수의 리턴 값으로 함수 안에 있는 변수의 값을 반환하였지만, 오류가 발생하지 않는 코드다.

이유는 const 키워드 때문이다.

 

const 참조자로 받으면 예외적으로 리턴 값의 생명이 연장된다.

int function()
{
    int a = 2;
    return a;
}
 
int main()
{
    const int& b = function();
    return 0;
}


정리하면, 다음과 같다.

 

  함수에서 값 리턴 (int f()) 함수에서 참조자 리턴 (int& f())
값 타입으로 받음
(int a = f())
값 복사됨 값 복사됨
다만 지역 변수의 레퍼런스를
리턴하지 않도록 주의
참조자 타입으로 받음
(int& a = f())
컴파일 오류 가능
다만 지역 변수의 레퍼런스를
리턴하지 않도록 주의
상수 참조자 타입으로 받음
(const int& a = f())
가능 가능
다만 지역 변수의 레퍼런스를
리턴하지 않도록 주의

 

728x90
반응형

'C++ > c++ basic' 카테고리의 다른 글

6. Wrapper 클래스 - 타입변환 연산자  (0) 2022.12.21
5. 연산자 오버로딩, friend 키워드  (0) 2022.12.21
4. implicit, explicit, mutable 키워드  (0) 2022.12.21
3. copy consturctor  (0) 2022.12.21
1. namespace  (0) 2022.12.21
Comments