This code compiles but I don't think it does what I intended, that is, move, don't copy, the boost::any object that was created on the stack into a std::vector<boost::any>
boost::any var;
var = std::string("StackOverflow");
std::vector<boost::any> vm;
vm.push_back(std::move(var));
for (auto& i : vm)
{
std::cout << boost::any_cast<std::string>(i) << std::endl; // yes a copy exists
}
std::cout << boost::any_cast<std::string>(var) << std::endl; // but this copy still exists too. was it not moved??
if you look into boost/any.hpp and observe its source code (at least find for move word) you can found that it is totally C++11 unaware (unfortunately)!
so you'd better to use boost::any::swap to simulate move assign (if you still want to use boost::any at all)
Related
I understand the difference between the two function variants.
My question is: should I normally use good old push_*() version and only switch to emplace_*() when my profiler tells me this will benefit performance (that is, do not optimise prematurely)? Or should I switch to using emplace_*() as the default (perhaps not to pessimise the code unnecessarily - similar to i++ vs ++i in for loops)?
Is any of the variants more universal than the other (that is, imposes less constraints on the type being inserted) in realistic non-contrived use cases?
While writing the code I would not worry about performance. Performance is for later when you already have code that you can profile.
I'd rather worry about expressiveness of the code. Roughly speaking, push_back is for when you have an element and want to place a copy inside the container. emplace_back is to construct the element in place.
Consider what has the lower "wtf-count":
struct foo {int x;int y;};
void foo_add(const foo& f,std::vector<foo>& v) {
v.emplace_back(f); // wtf ?!? we already have a foo
v.push_back(f); // ... simply make a copy (or move)
}
void foo_add(int x, int y, std::vector<foo>& v) {
auto z = foo{x,y}; // wtf ?!?
f.push_back(z); // why create a temporary?
f.emplace_back(x,y); // ... simply construct it in place
}
emplace functions are delegating constructors.
Let's say you have a container of T.
If you already have a T, maybe it's const, maybe it's a rvalue, maybe none of those;
Then you use push_xxx().
Your object will be copied/moved into the container.
If you instead want to construct a T, then you use emplace_xxx(), with the same parameters you would send the constructor.
An object will be constructed directly in the container.
Emplace functions are more generic than push functions. In no case they are less efficient, on the contrary - they can be more efficient, as they allow to optimize away one copy/move operation of the container element when you need to construct it from arguments. When putting an element into container involves copy/move anyway, emplace and push operations are equivalent.
Push can be preferable, if you actually want to enforce construction before copying/moving the element into the container. For example, if your element type has some special logic in its constructor that you want to execute before the container is modified. Such cases are quite rare, though.
If you switch from push_back to emplace_back in a naive way, you will have no advantage at all. Consider the following code:
#include <iostream>
#include <string>
#include <vector>
struct President
{
std::string name;
std::string country;
int year;
President(std::string p_name, std::string p_country, int p_year) :
name(std::move(p_name)), country(std::move(p_country)), year(p_year)
{
std::cout << "I am being constructed.\n";
}
President(President&& other) :
name(std::move(other.name)), country(std::move(other.country)),
year(other.year)
{
std::cout << "I am being moved.\n";
}
President& operator=(const President& other) = default;
};
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994);
std::vector<President> reElections;
std::cout << "\npush_back:\n";
reElections.push_back(
President("Franklin Delano Roosevelt", "the USA", 1936));
std::cout << "\nContents:\n";
for (President const& president : elections)
{
std::cout << president.name << " was elected president of "
<< president.country << " in " << president.year << ".\n";
}
for (President const& president : reElections)
{
std::cout << president.name << " was re-elected president of "
<< president.country << " in " << president.year << ".\n";
}
}
If you replace push_back by emplace_back you still have a construction and then a move. Only if you pass the arguments needed for construction instead of the constructed instance itself (see the call to emplace_back), you have saved effort.
Recently, I had the following
struct data {
std::vector<int> V;
};
data get_vector(int n)
{
std::vector<int> V(n,0);
return {V};
}
The problem with this code is that when the struct is created a copy occurs and the solution is instead to write return {std::move(V)}
Are there linter or code analyzer that would detect such spurious copy operations? Neither cppcheck, cpplint, nor clang-tidy can do it.
EDIT: Several points to make my question clearer:
I know that a copy operation occurred because I used compiler explorer and it shows a call to memcpy.
I could identify that a copy operations occurred by looking at the standard yes. But my initial wrong idea was that the compiler would optimize away this copy. I was wrong.
It is (likely) not a compiler problem since both clang and gcc produce code that produce a memcpy.
The memcpy may be cheap, but I cannot imagine circumstances where copying memory and deleting the original is cheaper than passing a pointer by a std::move.
The adding of the std::move is an elementary operation. I would imagine that a code analyzer would be able to suggest this correction.
I believe you have the correct observation but the wrong interpretation!
The copy will not occur by returning the value, because every normal clever compiler will use (N)RVO in this case. From C++17 this is mandatory, so you can't see any copy by returning a local generated vector from the function.
OK, lets play a bit with std::vector and what will happen during the construction or by filling it step by step.
First of all, lets generate a data type which makes every copy or move visible like this one:
template <typename DATA >
struct VisibleCopy
{
private:
DATA data;
public:
VisibleCopy( const DATA& data_ ): data{ data_ }
{
std::cout << "Construct " << data << std::endl;
}
VisibleCopy( const VisibleCopy& other ): data{ other.data }
{
std::cout << "Copy " << data << std::endl;
}
VisibleCopy( VisibleCopy&& other ) noexcept : data{ std::move(other.data) }
{
std::cout << "Move " << data << std::endl;
}
VisibleCopy& operator=( const VisibleCopy& other )
{
data = other.data;
std::cout << "copy assign " << data << std::endl;
}
VisibleCopy& operator=( VisibleCopy&& other ) noexcept
{
data = std::move( other.data );
std::cout << "move assign " << data << std::endl;
}
DATA Get() const { return data; }
};
And now lets start some experiments:
using T = std::vector< VisibleCopy<int> >;
T Get1()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec{ 1,2,3,4 };
std::cout << "End init" << std::endl;
return vec;
}
T Get2()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec(4,0);
std::cout << "End init" << std::endl;
return vec;
}
T Get3()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec;
vec.emplace_back(1);
vec.emplace_back(2);
vec.emplace_back(3);
vec.emplace_back(4);
std::cout << "End init" << std::endl;
return vec;
}
T Get4()
{
std::cout << "Start init" << std::endl;
std::vector< VisibleCopy<int> > vec;
vec.reserve(4);
vec.emplace_back(1);
vec.emplace_back(2);
vec.emplace_back(3);
vec.emplace_back(4);
std::cout << "End init" << std::endl;
return vec;
}
int main()
{
auto vec1 = Get1();
auto vec2 = Get2();
auto vec3 = Get3();
auto vec4 = Get4();
// All data as expected? Lets check:
for ( auto& el: vec1 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec2 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec3 ) { std::cout << el.Get() << std::endl; }
for ( auto& el: vec4 ) { std::cout << el.Get() << std::endl; }
}
What can we observe:
Example 1)
We create a vector from a initializer list and maybe we expect that we will see 4 times construct and 4 moves. But we get 4 copies! That sounds a bit mysterious, but the reason is the implementation of initializer list! Simply it is not allowed to move from the list as the iterator from the list is a const T* which makes it impossible to move elements from it. A detailed answer on this topic can be found here: initializer_list and move semantics
Example 2)
In this case, we get a initial construction and 4 copies of the value. That is nothing special and is what we can expect.
Example 3)
Also here, we the the construction and some moves as expected. With my stl implementation the vector grows by factor 2 every time. So we see a first construct, another one and because the vector resizes from 1 to 2, we see the move of the first element. While adding the 3 one, we see a resize from 2 to 4 which needs a move of the first two elements. All as expected!
Example 4)
Now we reserve space and fill later. Now we have no copy and no move anymore!
In all cases, we do not see any move nor copy by returning the vector back to the caller at all! (N)RVO is taking place and no further action is required in this step!
Back to your question:
"How to find C++ spurious copy operations"
As seen above, you may introduce a proxy class in between for debugging purpose.
Making the copy-ctor private may not work in many cases, as you may have some wanted copies and some hidden ones. As above, only the code for example 4 will work with a private copy-ctor! And I can not answer the question, if the example 4 is the fastest one, as we fill peace by peace.
Sorry that I can not offer a general solution for finding "unwanted" copies here. Even if you dig your code for calls of memcpy, you will not find all as also memcpy will be optimized away and you see directly some assembler instructions doing the job without a call to your library memcpy function.
My hint is not to focus on such a minor problem. If you have real performance issues, take a profiler and measure. There are so many potential performance killers, that investing much time on spurious memcpy usage seems not such a worthwhile idea.
I know that a copy operation occurred because I used compiler explorer and it shows a call to memcpy.
Did you put your complete application into the compiler explorer, and did you enable optimizations? If not, then what you saw in the compiler explorer might or might not be what is happening with your application.
One issue with the code you posted is that you first create a std::vector, and then copy it into an instance of data. It would be better to initialize data with the vector:
data get_vector(int n)
{
return {std::vector<int> V(n,0)};
}
Also, if you just give the compiler explorer the definition of data and get_vector(), and nothing else, it has to expect the worse. If you actually give it some source code that uses get_vector(), then look at what assembly is generated for that source code. See this example for what the above modification plus actual usage plus compiler optimizations can cause the compiler to produce.
I've seen my colleague do the second snippet quite often. Why is this? I've tried adding print statements to track the ctors and dtors, but both seem identical.
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ct1);
std::vector<ClassTest> vecClass2;
vecClass2.push_back(ClassTest());
ClassTest& ct2 = vecClass2.back();
ct2.blah = blah // set some stuff
...
PS. I'm sorry if the title is misleading.
Edit:
Firstly, thank you all for your responses.
I've written a small application using std::move. The results are surprising to me perhaps because I've done something wrong ... would someone please explain why the "fast" path is performing significantly better.
#include <vector>
#include <string>
#include <boost/progress.hpp>
#include <iostream>
const std::size_t SIZE = 10*100*100*100;
//const std::size_t SIZE = 1;
const bool log = (SIZE == 1);
struct SomeType {
std::string who;
std::string bio;
SomeType() {
if (log) std::cout << "SomeType()" << std::endl;
}
SomeType(const SomeType& other) {
if (log) std::cout << "SomeType(const SomeType&)" << std::endl;
//this->who.swap(other.who);
//this->bio.swap(other.bio);
this->who = other.who;
this->bio = other.bio;
}
SomeType& operator=(SomeType& other) {
if (log) std::cout << "SomeType::operator=()" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
return *this;
}
~SomeType() {
if (log) std::cout << "~SomeType()" << std::endl;
}
void swap(SomeType& other) {
if (log) std::cout << "Swapping" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
}
// move semantics
SomeType(SomeType&& other) :
who(std::move(other.who))
, bio(std::move(other.bio)) {
if (log) std::cout << "SomeType(SomeType&&)" << std::endl;
}
SomeType& operator=(SomeType&& other) {
if (log) std::cout << "SomeType::operator=(SomeType&&)" << std::endl;
this->who = std::move(other.who);
this->bio = std::move(other.bio);
return *this;
}
};
int main(int argc, char** argv) {
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"slow\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
SomeType some;
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
//store.push_back(SomeType());
//store.back().swap(some);
store.push_back(std::move(some));
}
}
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"fast\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
store.push_back(SomeType());
SomeType& some = store.back();
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
}
}
return 0;
}
Output:
dev#ubuntu-10:~/Desktop/perf_test$ g++ -Wall -O3 push_back-test.cpp -std=c++0x
dev#ubuntu-10:~/Desktop/perf_test$ ./a.out
Timing "slow" path
3.36 s
Timing "fast" path
3.08 s
If the object is more expensive to copy after "set some stuff" than before, then the copy that happens when you insert the object into the vector will be less expensive if you insert the object before you "set some stuff" than after.
Really, though, since you should expect objects in a vector to be copied occasionally, this is probably not much of an optimization.
If we accept that your colleague's snippet is wise, because ClassTest is expensive to copy, I would prefer:
using std::swap;
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ClassTest());
swap(ct1, vecClass1.back());
I think it's clearer, and it may well be more exception-safe. The ... code presumably allocates resources and hence could throw an exception (or else what's making the fully-built ClassTest so expensive to copy?). So unless the vector really is local to the function, I don't think it's a good idea for it to be half-built while running that code.
Of course this is even more expensive if ClassTest only has the default swap implementation, but if ClassTest doesn't have an efficient swap, then it has no business being expensive to copy. So this trick perhaps should only be used with classes known to be friendly, rather than unknown template parameter types.
As Gene says, std::move is better anyway, if you have that C++0x feature.
If we're worried about ClassTest being expensive to copy, though, then relocating the vector is a terrifying prospect. So we should also either:
reserve enough space before adding anything,
use a deque instead of a vector.
The second version benefits from moving the temporary. The first version is copying the temporary vector. So the second one is potentially faster. The second version has also potentially smaller peak memory requirements, the first version creates two objects one temporary and one copy of it and only then deletes the temporary. You can improve the first version by explicitly moving the temporary:
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(std::move(ct1));
You should probably ask your collegue to know exactly why, but we can still take a guess. As James pointed out, it might be a tad more efficient if the object is more expensive to copy once constructed.
I see advantages in both versions.
I like your collegue's snippet because: although there are 2 objects in both cases, they only co-exist for a very short period of time in the second version. There is only one object available for editing: this avoids the potential error of editing ct1 after push_back.
I like your personal snippet because: invoking push_back to add a second object potentially invalidates the reference ct2, inducing a risk of undefined behavior. The first snippet does not present this risk.
They are identical (as far as I can see). Maybe he or she does that as an idiomatic custom.
Am I doing something wrong (again)?
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map& pattern)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&& tmp)\n";
}
};
Map createMap()
{
return Map();
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2(Map(m1));//<<I thought that I create here tmp unnamed obj.
Map m3(createMap());//<<---or at least here, but nope...
return 0;
}
Please see the commented line in the code
Edited [taken from FredOverflow answer]
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2((Map(m1)));
std::cout << "\nmove\n";
Map m3(createMap());
}
I'm getting output:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)//Here why not move ctor aswell as copy?
move
Map()
Map()
Map(Map&& tmp)
Map m3(createMap());//<<---or at least here, but nope...
You are seeing return value optimization in action. In C++, the compiler is allowed to optimize away copying returned objects, and let the function work directly with the caller's object where the result is stored. There isn't any need to invoke the move constructor either.
Make the function more complicated, so that the compiler cannot use the optimization, and you'll see moving in action. For example:
Map createMap()
{
Map a, b;
if (rand())
return a;
return b;
}
You're declaring a function, not an object:
T name (T(blah));
Is equivalent to:
T name(T blah);
Which is recognizable as a function declaration. You can use extra parens:
Map m2 ((Map(m1)));
This is called the most vexing parse.
I slightly modified your main routine to understand the output better:
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2(Map(m1));
std::cout << "\nmove\n";
Map m3(createMap());
}
And here is the output with g++ -fno-elide-constructors:
default
Map()
copy
Map(const Map& pattern)
move
move
Map()
Map(Map&& tmp)
Map(Map&& tmp)
As others already pointed out, Map m2(Map(m1)); is indeed a function declaration, so you get no output. The second move is not interpreted as a function declaration, because createMap is not a type name. There are two move constructors involved here. One moves the temporary object created by evaluating Map() into the temporary object created by evaluating createMap(), and the second move initializes m3 from the latter. This is exactly what one would expect.
If you fix the first move by writing Map m2((Map(m1))); the output becomes:
move
Map(const Map& pattern)
Map(Map&& tmp)
Again, no surprises. The copy constructor is invoked by evaluating Map(m1), and that temporary object is then moved into m2. If you compile without -fno-elide-constructors, the move operations disappear, because they are replaced by even more efficient optimizations like RVO or NRVO:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)
move
Map()
I'm sure Visual C++ has a compiler option similar to -fno-elide-constructors that you can play with to understand move semantics better.
This program shows expected output.
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map&)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&&)\n";
}
};
Map createMap()
{
Map m;
return m;
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2 = createMap();//<<I thought that I create here tmp unnamed obj.
std::cin.get();
return 0;
}
Note the changes to createMap(). It doesn't employ a direct temporary but a named return value. This program shows the intended output on Visual Studio 2010.
Map createMap()
{
return Map();
}
I would think that the compiler would've done an RVO (return value optimization) on the above, thus no temporaries would ever be created.
If you change it to the following, you should see your move ctor getting invoked.
Map createMap()
{
Map m;
m.DoSomething(); // this should make the compiler stop doing RVO
return m;
}
Some compilers do RVO regardless of compiler settings (debug / release mode) - e.g. bcc32. I have a feeling VC would be the same.
I am interested if creating a new std::vector (or calling its assign method) creates a copy of the data?
For example,
void fun(char *input) {
std::vector<char> v(input, input+strlen(input));
// is it safe to assume that the data input points to was COPIED into v?
}
Yes. Elements are always copied into or out of STL containers. (At least until move semantics are added in C++0x)
EDIT: Here's how you can test for copying yourself:
#include <vector>
#include <iostream>
class CopyChecker
{
public:
CopyChecker()
{
std::cout << "Hey, look! A new copy checker!" << std::endl;
}
CopyChecker(const CopyChecker& other)
{
std::cout << "I'm the copy checker! No, I am! Wait, the"
" two of us are the same!" << std::endl;
}
~CopyChecker()
{
std::cout << "Erroap=02-0304-231~No Carrier" << std::endl;
}
};
int main()
{
std::vector<CopyChecker> doICopy;
doICopy.push_back(CopyChecker());
}
The output should be:
Hey, look! A new copy checker!
I'm the copy checker! No, I am! Wait, the two of us are the same!
Erroap=02-0304-231~No Carrier
Erroap=02-0304-231~No Carrier
Elements are always copied into or out of STL containers.
Although the element may just be a pointer, in which case the pointer is copied but not the underlying data
About the move semantics, here is how you could move the contents in C++0x if you wanted to:
void fun_move(char *input)
{
std::vector<char> v;
auto len = strlen(input);
v.reserve(len);
std::move(input, input+len, std::back_inserter(v));
}
If you want your data to be moved, use std::swap_ranges, but you have to allocate for memory first :
vector<T> v;
v.reserve(std::distance(beg, end));
std::swap_ranges(beg, end, v.begin());
If you do not want the object copy semantics, then you can create a vector of pointers-to-objects instead so that only the pointer is copied. However you then have to ensure that the pointers then remain valid for the lifetime of the container.