icon안동민 개발노트

참조자 (Reference)


참조자 개요

 참조자는 기존 변수의 별명(alias)으로, 동일한 메모리 위치를 가리키는 또 다른 이름입니다. 참조자를 사용하면 변수에 간접적으로 접근할 수 있으며, 포인터와 유사하지만 더 안전하고 사용하기 쉽습니다.

참조자 선언과 초기화

 참조자는 선언과 동시에 초기화해야 합니다.

#include <iostream>
 
int main() {
    int x = 10;
    int& ref = x;  // x에 대한 참조자 선언
 
    std::cout << "x = " << x << std::endl;
    std::cout << "ref = " << ref << std::endl;
 
    ref = 20;  // x의 값도 변경됨
    std::cout << "After modification:" << std::endl;
    std::cout << "x = " << x << std::endl;
    std::cout << "ref = " << ref << std::endl;
 
    return 0;
}

참조자 vs 포인터

 참조자와 포인터의 주요 차이점

  1. 참조자는 반드시 초기화해야 합니다.
  2. 참조자는 재할당이 불가능합니다.
  3. 참조자는 널(null) 값을 가질 수 없습니다.
예제
#include <iostream>
 
int main() {
    int x = 10;
    int* ptr = &x;  // 포인터
    int& ref = x;   // 참조자
 
    std::cout << "Using pointer: " << *ptr << std::endl;
    std::cout << "Using reference: " << ref << std::endl;
 
    // 포인터 재할당
    int y = 20;
    ptr = &y;
    std::cout << "After pointer reassignment: " << *ptr << std::endl;
 
    // 참조자는 재할당 불가능
    // ref = y;  // 이는 x의 값을 y의 값으로 변경하는 것임
 
    return 0;
}

const 참조자

 const 참조자는 참조하는 값을 수정할 수 없게 합니다.

#include <iostream>
 
int main() {
    int x = 10;
    const int& constRef = x;
 
    std::cout << "constRef = " << constRef << std::endl;
 
    // constRef = 20;  // 오류: const 참조자를 통한 수정 불가
    x = 20;  // 원본 변수는 수정 가능
    std::cout << "After modifying x: constRef = " << constRef << std::endl;
 
    return 0;
}

참조자와 함수

 참조자는 함수 매개변수로 자주 사용되며, 값의 복사 없이 효율적으로 데이터를 전달합니다.

#include <iostream>
 
void modifyValue(int& value) {
    value *= 2;
}
 
void printValue(const int& value) {
    std::cout << "Value: " << value << std::endl;
}
 
int main() {
    int x = 10;
    
    std::cout << "Before modification:" << std::endl;
    printValue(x);
 
    modifyValue(x);
 
    std::cout << "After modification:" << std::endl;
    printValue(x);
 
    return 0;
}

참조 반환

 함수에서 참조를 반환할 수 있습니다. 이는 효율적이지만 주의가 필요합니다.

#include <iostream>
#include <vector>
 
int& getElement(std::vector<int>& vec, int index) {
    return vec[index];
}
 
int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};
 
    std::cout << "Before modification:" << std::endl;
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
 
    getElement(numbers, 2) = 100;  // 3번째 요소를 100으로 변경
 
    std::cout << "After modification:" << std::endl;
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
 
    return 0;
}

오른값 참조 (C++ 11)

 C++ 11에서 도입된 오른값 참조는 이동 의미론(move semantics)과 완벽 전달(perfect forwarding)을 구현하는 데 사용됩니다.

#include <iostream>
 
void printReference(int& x) {
    std::cout << "Left value reference: " << x << std::endl;
}
 
void printReference(int&& x) {
    std::cout << "Right value reference: " << x << std::endl;
}
 
int main() {
    int a = 10;
    printReference(a);  // 왼값 참조
    printReference(20); // 오른값 참조
 
    return 0;
}

연습 문제

  1. 두 변수의 값을 교환하는 swap 함수를 참조자를 사용하여 구현하세요.
  2. 벡터의 모든 요소를 두 배로 만드는 함수를 작성하세요. 이 함수는 벡터를 참조로 받아야 합니다.
  3. 참조자를 반환하는 함수를 만들고, 이를 이용해 객체의 내부 상태를 수정하는 예제를 구현하세요.


참고 자료