C++11 이후와 이전으로 개념이 조금 바뀜
C++11 이후의 개념으로 설명합니다
정의 :
lvalue (locator value): 메모리 상에 지속적인 주소를 가지고 있으며, 다른 변수에 할당되거나 &* 연산자를 통해 그 위치를 참조할 수 있다.
[ 세 조건 다 맞아야 함 ]
rvalue (read value): 저장되거나 참조될 수 없고 오직 읽혀질 수만 있는 표현식의 결과, 한번만 쓰이고 다시 불릴 수 없는
[ 좌측값이 아닌 값 ]
위와 같이 left right 가 아닌 메모리에 지속적인 주소가 있는가, 읽기 전용 인가의 차이다.
- 따라서 &(L-val)는 가능하나, &(R-val)는 불가능함.
ex) 상수 "3"은 rvalue 임. 왜냐면 "3"은 메모리 상에 지속적인 주소를 가지지만, 저장되거나 참조될 수 없고 오직 읽을 수만(only read) 있고 값을 변경할 수 없는 객체 이기 때문이다.
Rvalue 참조 시키는 방법
1
int&& Lvalue = Rvalue;
ex)
int&& c = 3; --->> int b = 1; int* c = &b; int& d = *c; 이런 역할을 가진다 생각하면 됨 <- 대신 변수의 메모리 할당이 아주 짧게 이뤄지고 삭제 된다.
2
const int& Lvalue = Rvalue;
( int& 이지만 const로 변경하지 않는다는 보장을 하기 때문에 Rval 도 가능 )
ex)
const int& d = 4;
------
메모리 할당 예시
r-val 참조의 경우 0x12 byte 가 할당되는 걸 볼 수 있고
추가로 변수의 메모리 할당이 아주 짧게 이뤄지고 삭제 되서, 다음 메모리 할당값이 Rval가 할당된 메모리 이전 부터 할당되는 걸 볼 수 있다.
#include <iostream>
using namespace std;
void doSomething(int& lref) { cout << "L-value ref" << endl; }
void doSomething(int&& rref) { cout << "R-value ref" << endl; }
int getResult() { return 100; }
int main()
{
int x = 5;
int y = getResult();
const int cx = 6;
const int cy = 7;
const int return_cy = 8;
int &&rf = 9;
int tmp = 10;
int tmp2 = 11;
cout << &(x) << endl; // 0x7ffd868cc9f0 // 0x4
cout << &(y) << endl; // 0x7ffd868cc9f4 // 0x4
cout << &(cx) << endl; // 0x7ffd868cc9f8 // 0x4
cout << &(cy) << endl; // 0x7ffd868cc9fc // 0x4
cout << &(return_cy) << endl; // 0x7ffd868cca00 // 0x4
cout << &(rf) << endl; // 0x7ffd868cca0c // 0x12 // int b = 1; int* c = &b; int& d = *c; <- 주소가 3개 할당 0x4*3 = 0x12
cout << &(tmp) << endl; // 0x7ffd868cca04 // -0x8 // int &&rf = 9; 에서 r-val reference 는 짧게 메모리 할당후 해제 되므로 "0x7ffd868cca00" 부터 재할당함.
cout << &(tmp2) << endl; // 0x7ffd868cca08 // 0x4
}
------
#include <iostream>
#include <string>
using namespace std;
class Monitor
{
const int bb; // 메모리 할당 전
public:
explicit Monitor() : bb(0) { // 메모리 할당 시기 ( const int bb 를 0으로 초기화 )
std::cout << "Monitor 생성자 호출" << std::endl;
}
~Monitor() {
std::cout << "Monitor 소멸자 호출" << std::endl;
}
string class_name = "Monitor_member_variable";
};
Monitor class_1() {
Monitor* addr_m = new Monitor; // 추가로 동적 할당된 Monitor 객체는 삭제(delete)가 이뤄지지 않았기 때문에 메모리 누수를 발생 시킬 수 있다. // 사실 new 객체 생성시 자동 해제함
Monitor& ref_m = *addr_m;
return ref_m; // 함수가 끝나면, 리턴값(ref_m)이 참조하는 객체의 복사본이 임시 객체로 생성되고 return되기 떄문에 이 임시 객체는 rvalue 이다.
}
int func_1() { int t=1; return t; }
int main()
{
// Rvalue 참조 방법
Monitor&& ins_1 = class_1(); //
const Monitor& ins_2 = class_1(); // int& 이지만 const로 변경하지 않는다는 보장을 하기 때문에 Rval 도 가능
cout << ins_1.class_name << endl; // 출력값 : Monitor_member_variable
cout << ins_2.class_name << endl; // 출력값 : Monitor_member_variable
// cout << &(class_1()) << endl; // &(Rval) 불가능 , &(Lval) 가 가능
cout << "------------------------------------" << endl;
// 둘다 임시 객체를 생성해 그 임시 객체에 대한 참조를 가능케 해서 Rvalue 의 수명을 연장 시키는 방법이다.
int&& a = func_1(); // Rvalue 를 주소에 할당 시키는 방법 1
cout << a << endl; // 출력값 : 1
cout << &a << endl; // 출력값 : 0x7ffcdf4e20a0
const int& b= 3; // Rvalue 를 주소에 할당 시키는 방법 2 but 수정이 불가능 하다
cout << b << endl; // 출력값 : 3
cout << *(&b) << endl; // 출력값 : 3
cout << "------------------------------------" << endl;
// Lvalue 참조 방법
int t1 = 1;
int& ref_a = t1;
cout << ref_a << endl; // 출력값 : 1
cout << &ref_a << endl; // 출력값 : 0x7ffcdf4e2098
int t2 = 2;
int* point_b = &t2;
cout << *point_b << endl; // 출력값 : 2
cout << point_b << endl; // 출력값 : 0x7ffcdf4e209c
int&& c = 3;
const int& d = 4;
c = 5;
cout<< c << endl; // 출력값 : 5
}
메모리 누수
하단에 내용은 동적 할당( heap )을 했으나 delete(삭제) 시키지 않은 경우 메모리 누수가 날 수 있다.
메모리 누수를 피하려면 2가지 방법이 있다.
1. heap 말고 stack 에 저장해 객체 리턴
2. 스마트 포인터 사용
Monitor class_1() {
Monitor* addr_m = new Monitor;
Monitor& ref_m = *addr_m;
return ref_m;
}
int main()
{
Monitor&& ins_1 = class_1();
cout << ins_1.class_name << endl;
cout << "------------------------------------" << endl;
1. heap 말고 stack 에 저장해 객체 리턴
2. 스마트 포인터 사용
'언어 정리 > C++_개념_lib' 카테고리의 다른 글
typedef (0) | 2024.01.03 |
---|---|
#if, 초기화리스트, const, namespace (0) | 2024.01.02 |
template 설명 [ fold_expression ] (0) | 2023.12.27 |
가변인자 (1) | 2023.12.27 |
참조와 포인터 (0) | 2023.12.26 |
댓글