일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 순회
- 숫자
- mutable
- Basic
- 연결 리스트
- linked list
- 바이낸스
- 오버로딩
- array
- template
- 선물
- BST
- SCM
- 후위
- Data Structure
- 자료구조
- 기초
- 문자열
- trading view
- Tree
- 전위
- #선물 #비트코인#알트코인#매매#코인#마진
- C++
- 알고리즘
- Python
- 이진 탐색 트리
- 템플릿 함수화
- 트리
- 비트코인
- Windows
- Today
- Total
Project Hub
2. reference 본문
이전 글
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()) |
가능 | 가능 다만 지역 변수의 레퍼런스를 리턴하지 않도록 주의 |
'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 |