Skip to content

Instantly share code, notes, and snippets.

@brookinc
Created July 31, 2019 17:15
Show Gist options
  • Save brookinc/4c8e7965e6758f81e4162f8ddd03b824 to your computer and use it in GitHub Desktop.
Save brookinc/4c8e7965e6758f81e4162f8ddd03b824 to your computer and use it in GitHub Desktop.
Comparison of various push_back() / emplace_back() approaches.
// https://www.onlinegdb.com/online_c++_compiler
// https://stackoverflow.com/questions/35404932/stdvectoremplace-back-and-stdmove
// https://stackoverflow.com/questions/11572669/move-with-vectorpush-back
#include <iostream>
#include <utility>
#include <vector>
int main()
{
struct MyStruct {
MyStruct() : myInt(-1) {
printf("MyStruct empty constructor\n");
}
MyStruct(int someInt) : myInt(someInt) {
printf("MyStruct constructor\n");
}
MyStruct(const MyStruct& other) : myInt(other.myInt) {
printf("MyStruct copy constructor\n");
}
MyStruct(MyStruct&& other) :
myInt(std::exchange(other.myInt, -1)) {
printf("MyStruct move copy constructor\n");
}
MyStruct operator=(const MyStruct& other) {
myInt = other.myInt;
printf("MyStruct assignment operator\n");
return *this;
}
MyStruct operator=(MyStruct&& other) {
myInt = std::exchange(other.myInt, -1);
printf("MyStruct move assignment operator\n");
return *this;
}
int myInt;
};
// MyStruct test cases
int i = 0;
std::vector<MyStruct> someVector;
someVector.reserve(16);
printf("\ncase %d:\n", i++);
// PERFORMANCE: MEDIOCRE -- results in one call to constructor + copy constructor
// READABILITY: GOOD -- intention is clear
// FLEXIBILITY: GOOD -- allows modification after construction
MyStruct obj0(0);
someVector.push_back(obj0);
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: GOOD -- intention is clear
// FLEXIBILITY: LIMITED -- no modification after construction (would have to retrieve a reference if needed)
someVector.push_back(MyStruct(0));
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: MEDIOCRE -- intention is clear, but silently leaves the argument variable in an undefined state
// FLEXIBILITY: GOOD -- allows modification after construction
// SIDE EFFECTS / NOTES: leaves argument variable in an undefined state
MyStruct obj1(0);
someVector.push_back(std::move(obj1));
printf("obj1 = %d\n", obj1.myInt);
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: MEDIOCRE -- the std::move() is unnecessary
// FLEXIBILITY: LIMITED -- no modification after construction (would have to retrieve a reference if needed)
someVector.push_back(std::move(MyStruct(0)));
printf("\ncase %d:\n", i++);
// PERFORMANCE: EXCELLENT -- results in one call to constructor
// READABILITY: GOOD -- intention is clear
// FLEXIBILITY: LIMITED -- no modification after construction (would have to retrieve a reference if needed)
someVector.emplace_back(0);
printf("\ncase %d:\n", i++);
// PERFORMANCE: MEDIOCRE -- results in one call to constructor + copy constructor
// READABILITY: MEDIOCRE -- emplace_back() suggests in-place construction, but this is really just a push_back()
// FLEXIBILITY: GOOD -- allows modification after construction
MyStruct obj3(0);
someVector.emplace_back(obj3);
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: MEDIOCRE -- emplace_back() suggests in-place construction, but this is really just a push_back()
// FLEXIBILITY: LIMITED -- no modification after construction (would have to retrieve a reference if needed)
someVector.emplace_back(MyStruct(0));
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: MEDIOCRE -- emplace_back() suggests in-place construction, but this is really just a push_back(), and silently leaves the argument variable in an undefined state
// FLEXIBILITY: GOOD -- allows modification after construction
// SIDE EFFECTS / NOTES: leaves argument variable in an undefined state
MyStruct obj4(0);
someVector.emplace_back(std::move(obj4));
printf("obj4 = %d\n", obj4.myInt);
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to constructor + move copy constructor
// READABILITY: MEDIOCRE -- emplace_back() suggests in-place construction, but this is really just a push_back(), and the std::move() is unnecessary
// FLEXIBILITY: LIMITED -- no modification after construction (would have to retrieve a reference if needed)
someVector.emplace_back(std::move(MyStruct(0)));
#if __cplusplus > 201402L
printf("\ncase %d:\n", i++);
// PERFORMANCE: GOOD -- results in one call to empty constructor (followed by any manual value assignment as needed)
// READABILITY: GOOD -- intention is clear
// FLEXIBILITY: GOOD -- allows modification after construction
// SIDE EFFECTS / NOTES: C++17 only!
auto& obj5 = someVector.emplace_back();
obj5.myInt = 0;
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment