Created
July 31, 2019 17:15
-
-
Save brookinc/4c8e7965e6758f81e4162f8ddd03b824 to your computer and use it in GitHub Desktop.
Comparison of various push_back() / emplace_back() approaches.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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