emplace_back과 push_back은 '더 효율적인' 같은 수식어는 붙을 수 없다 입니다.
#include<vector>
#include<iostream>
int main(){
// Basic example
std::vector<int> foo;
foo.push_back(10);
foo.emplace_back(20);
// More tricky example
std::vector<std::vector<int>> foo_bar;
//foo_bar.push_back(10); // Throws error!!!!
foo_bar.emplace_back(20); // Compiles with no issue
std::cout << "foo_bar size: " << foo_bar.size() << "\n";
std::cout << "foo_bar[0] size: " << foo_bar[0].size() << "\n";
return 0;
}
이 코드를 보면, 'std::vector<std::vector<int>> foo_bar' 로 이중 벡터가 선언되어 있습니다.
push_back을 통하여 데이터를 넣으려면
vector<int> v{1, 2};
foo_bar.push_back(std::move(v));
이런 형식으로 데이터를 넣어야 하는데,
foo_bar.push_back(10); // Throws error!!!!
다음과 같이 넣어버리면, 오류가 발생합니다.
하지만 emplace_back에서는 오류가 발생하지 않습니다.
foo_bar.emplace_back(20); // Compiles with no issue
이는 foo_bar 안의 vector[0] 에게 20개의 새로운 요소를 생성하라는 것과 동일하기 때문에 이 일이 발생합니다.
( 즉, foo_bar안에서 20이라는 파라미터가 들어가게되면, 내부에서는 vector의 마지막 다음 요소에 20이란 값을 가지고 새로운 객체를 생성한다. 하지만 vector는 20이란 숫자가 들어가면, 20개의 크기를 할당하므로 이런일이 발생한다. )
emplace_back 내부의 생성
또한 축소 변환 등, 암시적인 변환에 대해 막기가 힘듭니다. 다음 예제를 보자.
#include <vector>
class A {
public:
explicit A(int /*unused*/) {}
};
int main() {
double foo = 4.5;
std::vector<A> a_vec{};
a_vec.emplace_back(foo); // No warning with Wconversion
//A a(foo); // Gives compiler warning with Wconversion as expected
}
컴파일 타임에서 에러를 잡아내지 못하기 때문에, 런타임에서 의도하지 않은 행동이 발생하게 된다.
위의 링크에서는 '다중 파라미터'를 이용하여 생성자를 호출할 때 사용하라고 적혀있다.
class Image {
Image(size_t w, size_t h);
};
std::vector<Image> images;
images.emplace_back(2000, 1000);
image 같은 데이터를 push_back을 이용하여 추가하려면 새로운 객체를 생성하고 push_back을 호출하여야 하는데,
생성자만을 이용하여 호출하면 '이동'을 하지 않으므로 조금 더 가볍게 사용할 수 있습니다.
즉 -> '이동' 작업이 비쌀 때만 사용하여야 합니다.
또한 C++17에서부터는 emplace_back을 사용하면, 삽입된 요소에 대한 참조를 반환합니다. 이를 사용할때도 사용합니다.
https://openmynotepad.tistory.com/10
'개발 🛠💻 > C++, Modern C++' 카테고리의 다른 글
c++ std::string - append(), += operator, + operator 비교 (0) | 2023.12.19 |
---|---|
GCC / G++ 차이점 (0) | 2023.12.05 |
C++ memory order 와 atomic 객체 (0) | 2023.11.02 |
C++17 std::optional (0) | 2023.09.08 |
[전문가를 위한 C++] 11장 11.1.6 레퍼런스와 포인터의 선택 기준 (0) | 2023.04.09 |
댓글