항목 41 : 값 전달 함수가 좋은 경우
아래 조건이 만족하면 사용자 정의 클래스 매개변수도 값전달이 유용할 수 있다.
1. 이동이 싸다
2. 함수가 해당 매개변수를 결국 내부에서 복사하는데 사용한다.
3. 복사 가능 타입
예시)
class Widget {
public:
void addName(const std::string& newName)
{ names.push_back(newName); }
void addName(std::string&& newName)
{ names.push_back(std::move(newName); }
...
}
class Widget {
public:
void addName(std::string newName)
{ names.push_back(std::move(newName)); }
...
}
여기서 값 전달의 이 점은 함수가 하나라는 점이다. 비용의 차이는 다음과 같다.
LValue
레퍼런스 : 복사 생성 1
값 : 복사 생성 1, 이동 생성 1
RValue
레퍼런스 : 이동 생성 1
값 : 이동 생성 2
값이 이동 생성 하나만 더 비싸기에 이동이 싸다면 나쁘지 않은 선택이다.
하지만 만약 내부에서 복사 생성이 아닌 대입을 하는 경우라면 값 전달 방식은 레퍼런스 방식에 비해 생성이 추가되므로 클래스의 생성 비용도 고려해야한다. 또한 부모 타입 매개변수에 자식 타입을 넣으면 값 전달은 잘림 문제가 있으므로 이 부분도 고려해야한다.
항목 41 : push_back vs emplace_back
std::vector<std::string> vs;
vs.push_back("abc"); // 1
vs.emplace_back("abc"); // 2
//s는 이미 있던 std::string
vs.push_back(s); // 3
vs.emplace_back(s); // 4
push_back은 T의 레퍼런스 타입을 받아 복사 대입을 한다.
emplace_back은 인자를 그대로 전달해 생성을 한다.
위 코드에서 3과 4의 성능은 같지만 1은 2에 비해 임시 객체가 하나 생성되기에 성능이 좋지 않다.
따라서 이런 경우 emplace_back을 쓰는게 좋다.
하지만 경우에 따라 push_back이 좋을 수 있다.
다음의 경우에는 높은 확률로 emplace_back이 성능이 좋다.
1. 추가할 값이 컨테이너에 대입이 아닌 생성될 때
push_back은 대입 시 복사 대입을 다이렉트로 하지만 emplace_back은 임시 객체 생성 후 이동 대입을 수행할 수 있기에 push_back이 더 효율적일 수 있다. (책에 정확히 안적혀 있어서 추측한거라 아닐 수도 있음...)
2. 인수 형식과 컨테이너 원소 타입이 다를때
위 코드의 경우에 해당함.
3. 컨테이너가 중복 방지 등에 의해 새 값을 거부할일이 없을때
중복 방지등이 필요한 컨테이너는 비교등을 위해 임시 객체가 필요한데 이때 emplace쪽이 더 성능이 안 좋을 수 있다.
추가로 성능과 별개로 아래 같은 경우에는 push_bakc이 좋다.
ptrs.push_back(std::shared_ptr<Widget>(new Widget, killWidget));
ptrs.emplace_back(new Widget, killWidget));
아래는 emplace_back 실행 중 예외 발생 시 누수가 발생한다.
사실 shared_ptr 생성 문장을 따로 분리하는게 가장 좋은데 이 경우에도 양쪽 성능이 같기 때문에 그냥 push_back쓰자.
마지막으로 emplace_back은 생성자 인자를 그대로 넘겨받는 것이기에 push_back과 달리 explicit 생성자로도 생성이 될 수 있다. 조심하자.
'프로그래밍 언어 > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 항목 35 ~ 40 : 동시성 API (1) | 2024.12.15 |
---|---|
[Effective Modern C++] 항목 31 ~ 34 : 람다 표현식 (0) | 2024.12.15 |
[Effective Modern C++] 항목 23 ~ 30 : 이동, 완벽 전달 (1) | 2024.11.23 |
[Effective Modern C++] 항목 18~22 : 스마트 포인터 (0) | 2024.11.10 |
[Effective Modern C++] 항목 7~17 : 현대적 C++ (2) | 2024.11.03 |