this code
#include <iostream>
#include <vector>
struct obj
{
std::string name;
int age;
float money;
obj():name("NO_NAME"),age(0),money(0.0f){}
obj(const std::string& _name, const int& _age, const float& _money):name(_name),age(_age),money(_money){}
obj(obj&& tmp): name(tmp.name), age(tmp.age), money(tmp.money) {}
obj& operator=(obj&&) {return *this;}
};
int main(int argc, char* argv[])
{
std::vector<obj> v;
for( int i = 0; i < 5000000; ++i )
{
v.emplace_back(obj("Jon", 45, 500.6f));
}
return(0);
}
is about 2 time slower than the equivalent with v.push_back(obj("Jon", 45, 500.6f)); and I don’t get why.
I have tested this with bot g++ 4.7.2 and clang++ 3.3.
Where I’m wrong ?
now that i have corrected my move construnctor i will add more
this is the emplace_back version
I’m testing this 2 with the time utility under Linux and compiling them with
g++-4.7 -std=c++11 -s -O3 -DNDEBUG
or
clang++ -std=c++11 -s -O3 -DNDEBUG
Not doing anything is better. You tried to make it faster (faster than what? did you actually profile before you wrote the move constructor?), but you broke it.
The compiler generates copy and move constructors and assignment operators for free, and she does it right. By deciding to write your own, you are telling the compiler that you know better, so she just gets out of the way and lets you
improvebreak it on your own.The first thing you broke, is that you made your move constructor actually copy. Things with a name are lvalues, and lvalues cannot be moved implicitly even if they are rvalue references. So the initializers need to actually call
std::move.The second thing you broke is that you didn’t make the move constructor declare that it does not throw by adding
noexceptto it. The compiler generated one had this. By not declaring that no exceptions are thrown, the implementation ofstd::vectorwill probably not use moves when reallocating the underlying storage: it cannot provide the strong exception guarantee without the assurance that moves don’t throw.Will doing all this make it perform better? Maybe. Maybe not. Your implementation may be doing the small string optimization on
std::string, and that means that there is no dynamic allocation: the whole string"Jon", being small, will be stored directly in thestd::stringobject. This makes a move have the same costs as a copy.You can make the whole
objstructure take advantage of a cheap move by allocating it dynamically, and usingunique_ptr. This will make moves cheaper than copies, even in the presence of the small string optimization. However, you are paying for that cheapness with the cost of allocation and extra indirection. Whether that is desirable or not only you can tell.