티스토리 뷰
[Effective Modern C++] 항목 32. 객체를 클로저 안으로 이동하려면 초기화 갈무리를 사용하라
pppgod 2020. 1. 12. 17:23이동 전용 객체들을 클로저 안으로 이동시키야 하는 경우를 알아보도록 하자. C++14 부터 새로운 갈무리 메커니즘을 도입하였다. 초기화 갈무리라는 것으로 다음과 같은 것을 할 수 있다.
class Widget {
public:
...
bool isValidated() const;
bool isProcessed() const;
bool isArchived() const;
private:
...
};
auto pw = std::make_unique<Widget>();
...
auto func = [pw = std::move(pw)]
{ return pw->isValidated()
&& pw->isArchived(); };
마지막 줄에 캡쳐절이 초기화 갈무리라는 것이다. 재미있게도 좌변과 우변의 범위가 다른데, 좌변은 클로저의 범위이고 우변은 람다가 정의되는 지점의 범위와 같다. 아래와 같이 직접 초기화도 가능하다.
auto func = [pw = std::make_unique<Widget>()]
{ return pw->isValidated()
&& pw->isArchived(); };
문제는 C++11 에서 위와 같은 코드가 불가능하다는 것이다. 다음과 같이 작성할 수는 있다.
class IsValAndArch {
public:
using DataType = std::unique_ptr<Widget>;
explicit IsValAndArch(DataType&& ptr)
: pw(std::move(ptr)) {}
bool operator()() const
{ return pw->isValidated() && pw->isArchived();}
private:
DataType pw;
};
auto func = IsValAndArch(std::make_unique<Widget>());
위의 코드로 동작하게는 만들었지만 작성해야할 코드량이 너무 많다. 다행히도 C++11 에서 비슷한 동작을 지원하는 std::bind 함수가 있다.
std::vector<double> data;
// C++14
auto func = [data = std::move(data)]
{ ... };
// C++11
auto func =
std::bind(
[](const std::vector<double>& data)
{ ... },
std::move(data)
);
std::bind 함수가 돌려주는 객체를 바인드 객체라고 부른다. 첫번째 인자는 호출 가능한 객체이고, 나머지는 그 객체에 전달할 값들을 나타낸다. 여기서 두번째 인자인 std::move(data) 가 전달하는 값이다. C++14 와의 차이점이라면 data 의 복사본을 사용한다는 것이다. 매개변수는 오른값이 전달되기는 했지만 람다 안에서 사용하는 data 는 복사본이기 때문이다. 위와 같은 이유로 상수성의 차이가 생기게 된다. 그 이유는 람다로부터 만들어진 클로저 클래스의 operator() 함수는 const 인데 반해 바인드로 이동 생성된 data 의 복사본은 const 가 아니기 때문이다. 그렇기 때문에 지금 보는 예제와 같이 const 에 대한 참조로 선언해야 한다. 만약 변이 가능한 람다를 사용하고 싶다면 mutable 로 선언하면 된다.
auto func =
std::bind(
[](std::vector<double>& data) mutable
{ ... },
std::move(data)
);
참고 서적
스콧 마이어스, Effective Modern C++
'C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 항목 34. std::bind보다 람다를 선호하라 (0) | 2020.01.18 |
---|---|
[Effective Modern C++] 항목 33. std::forward를 통해서 전달할 auto&& 매개변수에는 decltype을 사용하라 (0) | 2020.01.18 |
[Effective Modern C++] 항목 31. 기본 갈무리 모드를 피하라 (0) | 2020.01.11 |
[Effective Modern C++] 항목 30. 완벽 전달이 실패하는 경우들을 잘 알아두라. (0) | 2019.12.15 |
[Effective Modern C++] 항목 29. 이동 연산이 존재하지 않고, 저렴하지 않고, 적용되지 않는다고 가정하라 (0) | 2019.12.14 |
- Total
- Today
- Yesterday
- 보편 참조
- const
- std::forward
- Future
- Overloading
- Join
- 람다
- Override
- 보편참조
- async
- std::move
- 포인터
- Effective
- thread
- CPP
- Modern
- MOVE
- auto
- 발아시기
- Unreal
- forward
- Perfect
- detach
- Effective Modern C++
- Forwarding
- C++11
- C++
- 다이소
- C
- C++14
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |