C++ 참조자 및 짚고 갈 것
참조자의 도입
참조자: 또다른 이름이라고 컴파일러에게 알려주는 것이다.
ex) int& another_a = a; >> another_a는 a의 참조자다.
int형 변수의 참조자를 만들고 싶을 때 에는 int&처럼 가리키고자 하는 타입뒤에 &를 붙이면 된다.
※ another_a에 값을 대입하면 참조한 값에도 값이 변경된다.
참조자와 포인터는 상당히 유사한 개념이다.
주의할 점
- 레퍼런스는 반드시 처음에 누구의 별명이 될 것인지 지정해야한다.
- int& another_a; 이것은 불가능하다. = 으로 지정해줘야한다. <> int* p는 가능하다.
- 레퍼런스가 한번 별명이 되면 절대로 다른 것의 별명이 될 수 없다.
- 한 번 어떤 변수의 참조자가 되버린다면, 더이상 다른 변숮를 참조할수 없게 된다.
- int &another_a = a;라고 선언하고, another_a=b;가 된다면 a=b라는(=동치) 뜻이 된다.
- 레퍼런스는 메모리상에 존재하지 않을 수도 있다.
- int &another_a = a; 일때 another_a의 자리에 a를 다 바꾸면 되니깐 메모리상에 존재하지 않을수도 있다.
함수인자로 레퍼런스 받기
*기존에는 함수인자로 받는것이 int &p가안되는것으로 알았으나, 삽입되는 값에 &를 안붙힘으로 함수인자 레퍼런스 받음.
ex)
#include <iostream>
using namespace std;
int change(int &p){
p = 3;
return 0;
}
int main(){
int number = 5;
cout << number << endl;
change(number);
cout << number << endl;
{
를 실행하면
5
3
이 이출력된다.
상수에 대한 참조자
int &ref = 4;는 오류가 발생한다.
리터럴의 값을 바꾸는 것은 불가능하다.
※ const int &ref = 4; 와같이 상수 참조자로 선언한다면 리터럴도 참조할 수 있다.
int a = ref;는 a = 4; 와는 문장과 동일하게 처리된다.
레퍼런스의 배열과 배열의 레퍼런스
레퍼런스의 배열을 초기화 해주지 않고 레퍼런스 해줄 경우 오류가 발생한다.
주소값이 존재한다라는 의미는 해당 원소가 메모리 사이에서 존재한다. 라는 의미와 같다.
int(&ref)[3] = arr;
해당 부분과 같이 레퍼런스가 가능하다.
ref가 arr 를 참조하도록 하였다.
ref[0] 부터 ref[2]까지 각각 레퍼런스가 된다.
레퍼런스를 리턴하는 함수
int function(){
int a = 3;
return a;
}
int main(){
//function안에 정의된 a라는 변수의 값이 b에 복사되는 부분
int b = function();
return 0;
}
해당 코드가 실행되고 난 후 function()이 종료되고 나면 a는 메모리에서 사라지게 된다. 더이상 a는 사용할 수 없게된다.
int& function(){ //해당 함수의 리턴 타입은 &이다. 참조자를 리턴하게 된다.
int a = 3;
return a;
}
int main(){
//해당 부분으로 인해 function안에 있는 a는 함수의 리턴과 함께 사라진다.
int b = function();
b = 5;
return 0;
}
해당 코드를 실행하게 되면 구문 오류가 발생한다. function의 리턴타입은 int&이여서 참조자를 리턴을 한다. 그런데 참조하는 function안에 정의되어 있는 a가 사라지는 *댕글링 레퍼런스(Dangling reference)가 발생한다.
*댕글링 레퍼런스: 레퍼런스가 참조해야할 변수가 사라져서 혼자서 덩그러니 남아 있는 상황
외부변수의 레퍼런스를 리턴
int& function(int &a){
a = 3;
return a;
}
int main(){
int b = 2;
//b를 매개변수로 들어가게 되면 int &a = b이므로 아직 살아있는 b를 참조한다.
int c = function(b);
return 0;
}
해당 코드를 통해 위에서 발생하는 댕글링 레퍼런스를 방지할수 있다.
const를 통한 레퍼런스
#include <iostream>
using namespace std;
int function(){
int a = 6;
return a;
}
int main(){
const int& c = function();
cout << "c: " << c << endl;
return 0;
}
const int& c = function(); 리턴값을 참조자로 받았으나, const 참조자로 받았더니 문제없이 컴파일 되었다.
>> 원칙상은 문장이 끝나면 소멸되는것이 정상이나, 기존 int& 로 받았을 때에는 컴파일 자체가 안되었다.
예외적으로 상수 레퍼런스로 리턴값을 받게 되면 해당 리턴값의 생명이 연장된다. => 레퍼런스 사라질 때 까지\
C++의 시작인 new(), delete()
- new(), delete()를 왜 사용하는가
- 메모리관리는 프로그래밍에 중요한 소양이다. 또한, 정확하게 프로그램이 실행되기 위해서는 컴파일 시에 모든 변수의 주소값이 정확하여야한다. 하지만 많은 제약이 따르기 때문에 heap이라는 공간에 자유롭게 할당하고자 한다. C++에서 지원하는것은 new와 delete이며 이것을 이용하여 자유롭게 할당,해제등을 할 수 있다.
#include <iostream>
using namespace std;
int main(){
int* p = new int; //int 크기의 공간 할당
*p = 10;
cout << *p << endl;
delete p; //할당 공간 해제
return 0;
}
해당 공간이 아니라 무리하게 Heap이 아닌 공간을 해제하려한다면 경고메시지가 나타난다.
- new가 하는 일
- 메모리할당
- 생성자 호출
- 타입변환
- delete가 하는 일
- 소멸자 호출
- 메모리 해제