본문 바로가기

Programing/C++

[C++] Reference

728x90
반응형

 

오늘은 표준 입출력에 이어서 Reference에 대해 공부해보자.

 

레퍼런스 (Reference, 참조) 란?

 

이미 존재하는 변수(메모리)에 대한 추가적인 별칭(alias)를 부여 하는 문법

 

 

 

예시는 다음과 같다.

 

#include <iostream>

int main(int argc, const char * argv[]) {
    // insert code here...
    int n = 10;
    int*p = &n;
    int&r = n;
    
    r = 20;
    
    std::cout << n << std::endl;
    std::cout << &n << std::endl;
    std::cout << &r << std::endl;
}

 

 

 

위 코드를 그림으로 설명 하면 다음과 같다

 

 

 

int n = 10 코드가 실행 되면 0x7ff7bfeff2bc 주소에 int형의 10변수가 만들어지고 int*p = &n 을 통해 포인터 변수 p 가 0x7ff7bfeff2bc 주소를 가르키게 한다. 여기서  int&r = n; 을 통해 reference 변수 r이 동일하게 0x7ff7bfeff2bc 메모리를 가르키게 한다. 이 후에 r 변수의 값을 20으로 변경 하면 실제적으로 n의 값도 변경 되는 것을 볼 수 있다.

 

C++ 문법을 공부 하다 보면 &연산자에 대해 많은 혼란이 있다. 이에 간단히 정리를 하면 다음과 같다.

 

변수의 주소를 구할 때 사용 int n = 0; // 변수 선언 후
int*p = &n; // 변수의 주소를 구할 때
레퍼런스 변수를 선언할 때 사용 int&r = n;

 

 

 

 

레퍼런스와 함수 인자

 

함수 인자로 레퍼런스를 사용하는 예시를 들어보자

 

#include <iostream>

void inc1(int n) {++n;}
void inc2(int* p) {++(*p);}
void inc3(int& r) {++r;}


int main(int argc, const char * argv[]) {
    // insert code here...
    int a = 10, b = 10, c = 10;
    inc1(a);
    inc2(&b);
    inc3(c);
    
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
}

 

출력을 보면 a는 변경되지 않았고 b,c만 값이 변경 된 것을 볼 수 있다.

 

 

위의 코드를 그림으로 나타내면 다음과 같다.

 

 

 

이렇게 함수 인자로 Reference를 사용하면 아래의 장점이 있다

 

 - 포인터와 유사하게 전달된 인자의 값을 수정 할 수 있다.

 

 - 포인터 보다 "간결하고 안전하게" 코드를 작성 할 수 있다

 

 

여기서 안전하게 라는 뜻에 대해서 좀 더 깊이 있게 살펴 보면 

 

#include <iostream>

void f1(int* p)
{
    if (p != 0)
    {
        
    }
}

void f2(int& r)
{
    
}



int main(int argc, const char * argv[]) {
    // insert code here...
    int n = 10;
    int*p = 0; 
    int&r; // error
    int&r = n; // 초기화 필요
}

 

이 코드르 살펴 보면

 

int&r; 이 코드에서 Error 가 발생 한다. 포인터의 경우 널포인터는 있지만, 참조의 경우 널참조는 없기 때문에 error가 발생하는 것이다.

 

그렇기 때문에 널포인터가 있는 포인터를 함수 인자로 받을 경우 널포인터를 조사하는 구문이 추가해야 되는 경우가 발생 한다. 이것 때문에 레퍼런스가 포인터 보다 안전하게 코드를 작성 할 수 있다라는 의미 이다.

 

 

 

scanf vs std::cin

두 함수 모두 사용자가 입력한 값을 인자로 전달한 변수에 담아 와야 한다. 점에서 기능은 같다.

 

하지만 C언어의 출력 함수 scanf는 주소를 보내고(call by pointer), c++의 출력 함수 std::cin 은 그냥 변수를 보낸다. (call by reference)

 

scanf("%d", &n) call by pointer
std::cin >> n; call by reference

 

 

 

swap 함수

Swap 함수 구현을 C언어(pointer) C++언어(reference)로 비교하여 어떻게 다른지 확인해보자.

 

먼저 C 언어 Style로 Swap 함수를 구현하면

 

 

#include <iostream>

void swap(int*p1, int*p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}


int main(int argc, const char * argv[]) {
    // insert code here...
    int x = 10, y = 20;
    swap(&x, &y);
    
    std::cout << x << std::endl;
    std::cout << y << std::endl;
}

 

이렇게 x, y가 잘 바뀌어 출력 된 것을 볼 수 있다.

 

 

이번엔 C++ 언어 Style로 Swap함수를 구현해보자.

 

#include <iostream>

void swap(int&r1, int&r2)
{
    int temp = r1;
    r1 = r2;
    r2 = temp;
}


int main(int argc, const char * argv[]) {
    // insert code here...
    int x = 10, y = 20;
    swap(x, y);
    
    std::cout << x << std::endl;
    std::cout << y << std::endl;
}

 

해당 코드도  x, y가 잘 바뀌어 출력 된 것을 볼 수 있다.

 

 

C언어(pointer)로 구현한 것보다 C++로 구현 한 것이 더 읽기도 편하고 이해하기 한결 더 편한 것 같다.

 

 

반응형