Qaupot Blog
Software Engineering, Trip

106. reference

🕐 Mon, 17 Feb 2014 09:00:00 GMT 🕓 Tue, 24 Aug 2021 12:35:00 GMT

Reference

C의 포인터와 용도가 비슷하지만, 포인터는 메모리 공간의 주소를 담는 자료형인 것에 반해, 레퍼런스는 인스턴스 그 자체를 가르키는 의미로써 사용됩니다.

l-value reference

l-value reference 는 C++에서 전통적으로 의미하는 참조 방식입니다.

#include <iostream>
int main(int argc, char** argv)
{
    int value = 20;
    int& ref= value;

    printf("%d\n", ref);
    printf("%x %x", &ref,&value);
    return 0;
}

l-value reference 는 변수를 선언할때 자료형에 &를 하나 붙입니다.

  • 반드시 초기화가 함께 이루어져야 합니다. reference 는 단독으로 선언될 수 없습니다.

ref 는 완전히 value 라는 변수와 동일하게 취급됩니다.

  • 단순히 값 뿐만 아니라 주소까지 동일합니다.
  • l-value reference 가 데이터가 있는 메모리 공간 자체를 가르키는 것이기 때문입니다.

Call by Value

#include <iostream>
int plus(int op1, int op2)
{
    printf("plus address : %x %x\n", &op1, &op2);
    return op1 + op2;
}

int main(int argc, char** argv)
{
    int op1 = 20;
    int op2 = 15;
    printf("main address : %x %x\n", &op1, &op2);

    printf("answer : %d\n", plus(op1,op2));
    return 0;
}

일반적인 함수 호출입니다. op1과 op2를 plus 라는 함수에 넘겨 값을 계산했습니다.
main 함수와 plus 함수 내의 op가 주소 값이 다른 것을 확인할 수 있습니다.

이를 Call by Value (값에 의한 호출) 라고 부르며, op1과 op2는 plus 내의 지역 변수로써 복사되어 사용됩니다.

  • 함수 호출시 인수 전달은 기본적으로 값 복사를 통해 이루어집니다.
  • plus 함수 내에서 op1과 op2에 다른 값을 대입해도 main 함수의 op1과 op2는 영향을 받지 않습니다.

Call by Reference

#include <iostream>
int plus(int& op1, int& op2)
{
    printf("plus address : %x %x\n", &op1, &op2);
    return op1 + op2;
}

int main(int argc, char** argv)
{
    int op1 = 20;
    int op2 = 15;
    printf("main address : %x %x\n", &op1, &op2);

    printf("answer : %d\n", plus(op1,op2));
    return 0;
}

plus 함수의 인수를 레퍼런스로 변경했습니다.
main 함수와 plus 함수 내의 op가 주소 값이 같은 것을 확인할 수 있습니다.

이를 Call by Reference (참조에 의한 호출)라고 부릅니다.

  • plus 함수 내에서 op1과 op2에 값을 변경하면, main 함수의 op1과 op2 역시 영향을 같이 받게 됩니다.
  • Call by Value 에 비해 함수 호출 비용을 줄일 수 있습니다.
    • 인수를 복사하는 비용이 들어가지 않습니다.

C의 포인터를 이용해서도 Call by Reference 를 구현할 수는 있습니다.

포인터는 주소를 담는 자료형이기 때문에 밖에서 포인터를 넘기면, 메모리 조작으로 함수 내에서 외부의 변수에 영향을 줄 수 있습니다. 그러나 C++ l-value Reference 의 장점은 '메모리 공간이 있다' 라는 사실을 보장해 준다는 것입니다.

포인터는 자료형이기 때문에 엉뚱한 값을 대입해도 문법상 에러가 발생하지 않습니다. 그러나 레퍼런스는 반드시 공간이 있는 l-value 만을 받을 수 있기 때문에 상대적으로 안전합니다.

  • 흔한 경우는 아니지만, 레퍼런스를 취한 이후에 본래 변수가 소멸하는 경우에는 문제가 발생할 수 있습니다.

r-value reference (C++11)

r-value reference 는 C++11 부터 사용할 수 있는 참조 방식입니다.
l-value reference 와는 다르게 '임시 값'을 담는데 사용합니다.

r-value reference 는 자료형에 &&를 붙이며, 다시
named r-value referenceunnamed r-value reference 로 나뉩니다.

#include <iostream>

int plus(int&& op1, int&& op2)
{
    // 이 식은 사용할 수 없습니다.
    //int&& op3 = op1;

    printf("plus address : %x %x\n", &op1, &op2);
    return op1 + op2;
}

int main(int argc, char** argv)
{
    int op1 = 20;

    printf("answer : %d\n", plus(20+op1, 10));
    return 0;
}

본래 r-value 는 '임시 값' 이기 때문에 휘발성이며 명시적인 주소가 없습니다.

  • 20 + op1의 결과 값이나 10이란 값은 사용된 후 사라집니다.

named r-value reference 는 이 값을 잡아두어 l-value 처럼 사용할 수 있게 해줍니다.
생성된 named r-value reference 는 이름이 붙고 코드 내에서 활용될 수 있기 때문에, l-value 로 취급 되고, 다시 r-value reference 를 바로 취할 수 없습니다.

  • 따라서 int&& op3 = op1;는 사용할 수 없습니다.

하지만 std::move 함수를 이용해서 l-value 를 다시 r-value 처럼 취급되도록 할 수 있습니다.

int plus(int&& , int&& )
{
    printf("unnamed r-value");
    return 0;
}

위의 코드는 unnamed r-value reference 입니다. 변수 명이 지정되어 있지 않습니다.

  • 해당 값은 계속해서 r-value 로 유지되며, 제어할 수 없습니다.

l-value reference 의 특징이 확정된 메모리 공간이 있다는 것이였다면
named r-value reference 의 특징은 임시적인 메모리를 잡는 것입니다.

C++ 언어의 특성상 임시 값은 수 없이 만들어졌다가 사라집니다.
20 + 10 - op1 + 10 - op2처럼 조금 더 복잡한 식이 있다고 하면, 연산자 우선순위에 따라 차례로 계산합니다.

temp1 = 10 - op2;  
temp2 = -op1 + temp1;  
temp3 = 10 +temp2;  
temp4 = 20 + temp3;  

이 과정에서 임시 값이 4번이 생성 되었습니다.

이 경우는, int 를 사용했기 때문에 CPU 내의 레지스터에서 처리 될 수도 있지만,
많은 멤버변수를 가지고 있는 클래스가 위와 같은 연산을 반복할 경우, 여러 번의 복사가 발생하여 성능을 낮추는 원인이 됩니다.

temp = 10 - op2;  
temp = -op1 + temp;  
temp = 10 + temp;  
temp = 20 + temp; 

r-value reference 를 사용하면 위와 같은 임시 메모리 공간을 재활용 할 수 있는 알고리즘을 구성할 수 있습니다.

이 블로그는 개인 블로그입니다. 게시글은 오류를 포함하고 있을 수 있지만, 저자는 오류를 해결하기 위해 노력하고 있습니다.
게시글에 별도의 고지가 없는 경우, 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 라이선스를 따릅니다.

This blog is personal blog. published posts may contain some errors, but author doing efforts to clear errors.
If post have not notice of license, it under creative commons Attribution-NonCommercial-NoDerivatives 4.0.