01. Pointer vs. Reference
값, 포인터, 참조를 통해 전달하는 3가지 방식이 존재한다
값으로 전달을 하면 데이터를 전체 다 복사해야 한 경우가 발생한다
따라서, 포인터와 참조를 통해 전달하는 것이 효율적이다
둘의 차이는 내부적으로 없으며
참조의 경우는 const와 함께 작성해서 값을 변경하지 못하도록 막는 경우가 많다
void fooV(std::array<int,100> a)
{
int b = a+1;
};
void fooP(int * ap)
{
int b = *ap+1;
};
void fooR(const int & a)
{
int b = a+1;
a =100;
};
02. L-Value vs. R-Value
# L-Value vs. R-Value
R-Value는 한 번만 사용되고 더 이상 불려지거나 사용되지 않는 경우
L-Value는 계속 재사용되고 불려지는 경우
# Value vs. L-Value Ref vs. R-Value Ref
#include <string>
void storeByValue(std::string s)
{
std::string b = s;
};
void storeByLRef(std::string & s)
{
std::string b = s;
};
void storeByRRef(std::string && s)
{
//std::string b = s;// s가 계속 재사용될 수 있기 때문에
std::string b = std::move(s);
};
int main()
{
std::string a = "abc";
storeByValue(a);
storeByLRef(a);
//storeByRRef(a);// 오류가 발생한다
storeByRRef(std::move(a));// 1번 해결방식
storeByRRef("abc");// 2번 해결방식
}
위의 예제에서
Value를 이용하면, 2번 Copy
LRef를 이용하면, 1번 Copy
RRef를 이용하면, 0번 Copy가 일어난다
03. std::move()
# move
std::move는 소유권을 넘겨주면서
Lvalue를 Rvalue로 바꿔주는 것이다
# move 예시 1
"abc"에 대한 소유권이 a에서 b로 넘어갔기 때문에
마지막 줄에서 a는 출력되지 않는다
#include <string>
#include <iostream>
int main()
{
std::string a = "abc";
std::cout << a << std::endl;
std::string b = std::move(a);
std::cout << b << std::endl;
std::cout << a << std::endl;
}
# move 예시 2
LRef함수에서 s(a)에대한 소유권이 b로 넘어갔기 때문에
마지막 줄에서 a는 출력되지 않는다
#include <string>
#include <iostream>
void storeByLRef(std::string& s)
{
std::string b = std::move(s);
};
void storeByRRef(std::string&& s)
{
std::string b = std::move(s);
};
int main()
{
std::string a = "abc";
storeByLRef(a);
std::cout << a;
}
# move 예시 3
예시 2에서 LRef 함수에서는 Copy가 0번이지만
예시 3에서 처럼 LRef 함수의 인자에 const를 붙여주면
Copy가 발생한다
그래서 a가 정상적으로 출력된다
#include <string>
#include <iostream>
void storeByLRef(const std::string& s)// const를 추가
{
std::string b = std::move(s);
};
void storeByRRef(std::string&& s)
{
std::string b = std::move(s);
};
int main()
{
std::string a = "abc";
storeByLRef(a);
std::cout << a;
}
# 그럼 뭘써야하나?
Lval는 Copy 1번
Rval는 Copy 0번이 최상의 효율이고
이를 위해서는 인자에 값을 받고 함수 내부에서 std::move를 이용하면 된다
#include <string>
#include <iostream>
class Cat
{
public:
void setName_1(std::string name)// Lval Copy 2번 발생
{
mName = name;
};
void setName_2(std::string && name)// Lval를 받지 못해 컴파일 에러
{
mName = std::move(name);
};
void setName_3(std::string & name)// Rval Copy 0번 발생하지만, Lval s는 소유권이 사라짐
{
mName = std::move(name);
};
void setName_4(const std::string & name)// Lval Copy 1번, Rval Copy 1번
{
mName = std::move(name);
};
void setName_5(std::string name)// Lval Copy 1번, Rval Copy 0번 (최고 효율)
{
mName = std::move(name);
};
private:
std::string mName;
};
int main()
{
Cat kitty;
std::string s = "kitty";
kitty.setName_5(s); // 1 copy
kitty.setName_5("nabi");//0 copy, Copy elision을 통해 nabi는 복사되지 않음
}
04. RVO
# RVO 개념
Return Value Optimization은 리턴하는 값의 최적화를 해주는 기능이다
따라서 return 값에 move 사용하지 않아도 된다
# RVO 예시 1
#include <string>
std::string getString()
{
std::string s = "no";
//return std::move(s);// 해줄 필요 없음
return s;// RVO
}
int main()
{
std::string a = getString();
return 0;
}
위의 예제에서
RVO는
"no"라는 문자열이 Copy 되지 않게 하고
처음부터 s를 없는 취급 해서
소유권이 이동(move) 조차도 일어나지 않고
바로 a에 "no"를 연결시키는 작업을 한다
# RVO 예시 2 - Move Constructor
#include <string>
std::string getString(std::string a, bool b)
{
if (b)
{
a = "no";
}
return a; // RVO 개입 X
// return std::move(a);// Move Constructor로 Copy가 발생 안하니 작성 필요 없음
}
int main()
{
std::string a = getString("abc", 1);// Move Constructor
return 0;
}
위의 예제처럼
컴파일러가 복사된 a를 돌려줘야 할지 a에 바로 "no"를 연결해 줄지 알 수 없는 경우에는
RVO가 개입되지 않는다
그러나, RVO가 개입되지 않아도
이동 생성자가 실행이 되었기 때문에 Copy는 발생하지 않고
std::move를 return 값에 작성해주지 않아도 된다
# Copy Constructor vs. Move Constructor
#include <string>
int main()
{
std::string s = "abc";
std::string b = s;// Copy Constructor
std::string c = std::move(s);// Move Constructor
// Lvalue인 s가 Rvalue로 move되면서
// 소유권이 c에게 넘어가고 zero copy가 일어나며
// 복사 없이 소유권이 넘어가는 복사 생성자가 실행
return 0;
}
'C++ > [노코프] C++' 카테고리의 다른 글
[C++ NOTE] Smart Pointer (0) | 2024.03.29 |
---|---|
[C++ NOTE] Inheritance (0) | 2024.03.28 |
[C++ NOTE] OOP (0) | 2024.03.27 |
[C++ NOTE] Compile Process (0) | 2024.03.25 |
[C++ NOTE] Memory Structure (0) | 2024.03.24 |