I was trying to adapt some code and moving the content from a vector to another one using emplace_back()
#include <iostream>
#include <vector>
struct obj
{
std::string name;
obj():name("NO_NAME"){}
obj(const std::string& _name):name(_name){}
obj(obj&& tmp): name(std::move(tmp.name)) {}
obj& operator=(obj&& tmp) = default;
};
int main(int argc, char* argv[])
{
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back(obj("Jon"));
}
std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
p.emplace_back(v[i]);
}
return(0);
}
This code doesn't compile with g++-4.7, g++-4.6 and clang++: what it's wrong with it ?
I always got 1 main error about
call to implicitly-deleted copy constructor of obj
?
Although the existing answer provides a workaround using std::move that makes your program compile, it must be said that your use of emplace_back seems to be based on a misunderstanding.
The way you describe it ("I was trying to [...] moving the content from a vector to another one using emplace_back()") and the way you use it suggest that you think of emplace_back as a method to move elements into the vector, and of push_back as a method to copy elements into a vector. The code you use to fill the first instance of the vector seems to suggest this as well:
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back(obj("Jon"));
}
But this is not what the difference between emplace_back and push_back is about.
Firstly, even push_back will move (not copy) the elements into the vector if only it is given an rvalue, and if the element type has a move assignment operator.
Secondly, the real use case of emplace_back is to construct elements in place, i.e. you use it when you want to put objects into a vector that do not exist yet. The arguments of emplace_back are the arguments to the constructor of the object. So your loop above should really look like this:
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back("Jon"); // <-- just pass the string "Jon" , not obj("Jon")
}
The reason why your existing code works is that obj("Jon") is also a valid argument to the constructor (specifically, to the move constructor). But the main idea of emplace_back is that you need not create the object and then move it in. You don't benefit from that idea when you pass obj("Jon") instead of "Jon" to it.
On the other hand, in your second loop you are dealing with objects that were created before. There is no point in using emplace_back to move objects that exist already. And again, emplace_back applied to an existing object does not mean that the object is moved. It only means that it is created in-place, using the ordinary copy constructor (if that exists). If you want to move it, simply use push_back, applied to the result of std::move:
std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
p.push_back(std::move(v[i])); // <-- Use push_back to move existing elements
}
Further notes
1) You can simplify the loop above using C++11 range-based for:
std::vector<obj> p;
for (auto &&obj : v)
p.push_back(std::move(obj));
2) Regardless of whether you use an ordinary for-loop or range-based for, you move the elements one by one, which means that the source vector v will remain as a vector of 1000 empty objects. If you actually want to clear the vector in the process (but still use move semantics to transport the elements to the new vector), you can use the move constructor of the vector itself:
std::vector<obj> p(std::move(v));
This reduces the second loop to just a single line, and it makes sure the source vector is cleared.
The problem is that
p.emplace_back(v[i]);
passes an lvalue to emplace_back, which means that your move constructor (which expects an rvalue reference) won't work.
If you actually want to move values from one container to another, you should explicitly call std::move:
p.emplace_back(std::move(v[i]));
(The idea behind a move constructor like obj(obj&& tmp) is that tmp should be an object that isn't going to be around for much longer. In your first loop, you pass a temporary object to emplace_back, which is fine -- a rvalue reference can bind to a temporary object and steal data from it because the temporary object is about to disappear. In your second loop, the object that you pass to emplace_back has a name: v[i]. That means it's not temporary, and could be referred to later in the program. That's why you have to use std::move to tell the compiler "yes, I really meant to steal data from this object, even though someone else might try to use it later.")
Edit: I'm assuming that your rather unusual usage of emplace_back is a relic of having to craft a little example for us. If that isn't the case, see #jogojapan's answer for a good discussion about why using a std::vector move constructor or repeated calls to push_back would make more sense for your example.
Related
My code looks like the following:
#include <list>
#include <thread>
void my_function(int val) {
// Empty function
}
int main() {
std::list<std::thread> threads;
for (int i = 0 ; i < 10 ; i++) {
threads.push_back(std::thread(my_function, i));
}
return 0;
}
The fact that I use threads.push_back() means that I run the copy-constructor std::thread::thread(const thread&).
Is it safe?
Should I use std::move ?
Please suppose that I don't know in advance how many threads I am going to need, so replacing the list by an array or by an std::vector, is not an option for me (std::vector would be an option only if I knew the number of threads in advance, as I cannot afford the vector's realloc operations).
The fact that I use threads.push_back() means that I run the copy-constructor
No, it does not. Since C++11 push_back is overloaded to accept an rvalue reference to the list's value type.
You cannot run std::thread's copy constructor, since it's declared as deleted. The above mentioned overload of push_back was added for this exact purpose of supporting move only types, like a thread handle.
If you want to initialize the thread directly into the container without a move, then emplace_back can do that. But you need to pass the parameters for the std::thread constructor in, not a thread that is initialized from them:
threads.emplace_back(my_function, i);
I would like to know whether it is ever necessary to move values explicitly when I am not inside a move constructor / move assignment. Lets say I have the following situation:
struct Node
{
std::vector<int> items;
};
Node create()
{
std::vector<int> items;
items.push_back(2);
Node n;
// should I use n.items = std::move(items);
// instead?
n.items = items;
// other code, not using items any more
return n;
}
First of all, is it correct to move an lvalue using std::move provided that I don't use the moved value any more in subsequent code?
Secondly, is it faster to move the value explicitly or does the compiler automatically detect that value can be moved?
You may avoid moving and leave it to initialization of an object and optimization of the compiler:
struct Node
{
std::vector<int> items;
};
Node create()
{
std::vector<int> items;
// ...
return Node{items};
}
The usual advice is: Do not apply overhasty manual optimizations.
Moving an lvalue is fine so long as you remember that lvalue might not be valid anymore. You can copy something over it and it'll be fine once again, though.
Moving the contents of a vector is generally faster than copying it as it only has to swap the underlying pointer (and a size variable) rather than individually copying each element in the vector. Moving something simple, like an int, is kind of silly, though.
Finally, in your example, it certainly wouldn't hurt to be explicit. items is an lvalue, so unless your compiler is clever enough to see items is never used again at all, it probably will use the copy semantics, so being explicit would help.
If structs are fully copied, then the first loop is more expensive than the second one, because it is performing an additional copy for each element of v.
vector<MyStruct> v;
for (int i = 0; i < v.size(); ++i) {
MyStruct s = v[i];
doSomething(s);
}
for (int i = 0; i < v.size(); ++i) {
doSomething(v[i]);
}
Suppose I want to write efficient code (as in loop 2) but at the same time I want to name the MyStruct elements that I draw from v (as in loop 1). Can I do that?
Structs (and all variables for that matter) are indeed fully copied when you use =. Overloading the = operator and the copy constructor can give you more control over what happens, but there is no way you can use these to change the behavior from copying to referencing. You can work around this by creating a reference like this:
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i]; //& creates reference; no copying performed
doSomething(s);
}
Note that the struct will still be fully copied when you pass it to the function, unless the argument is declared as a reference. This is a common pattern when taking structs as arguments. For instance,
void doSomething(structType x);
Will generally perform poorer than
void doSomething(const structType& x);
If sizeof structType is greater than sizeof structType*. The const is used to prevent the function from modifying the argument, imitating pass-by-value behavior.
In your first example, the object will be copied over and you will have to deal with the cost of the overhead of the copy.
If you don't want the cost of the over head, but still want to have a local object then you could use a reference.
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i];
doSomething(s);
}
You can use references or pointers to avoid copying and having a name to relate to.
vector<MyStruct> v;
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i];
doSomething(s);
}
However since you use a vector for your container, using iterators might be a good idea. doSomething should take argument by const ref though otherwise, you'll still copy to pass argument to it.
vector<MyStruct> v;
for (vector<MyStruct>::iterator it = v.begin(); it != v.end(); ++it) {
doSomething(*it);
}
In your examples, you are creating copies. However not all uses of operator '=' will result in a copy. C++11 allows for 'move construction' or 'move assignment' in which case you aren't actually copying the data; instead, you're just (hopefully) making a high-speed move from one structure to another. (Naturally, what it ACTUALLY does is entirely dependent upon how the move constructor or move assignment operator is implemented, but that's the intent.)
For example:
std::vector<int> foo(); // returns a long vector
std::vector<int> myVector = std::move(foo());
Will cause a MOVE construction, which hopefully just performs a very efficient re-pointing of the memory in the new myVector object, meaning that you don't have to copy the huge amount of data.
Don't forget, however, about the return-value optimization, as well. This was just a trivial example. RVO is actually superior to move semantics when it can be used. RVO allows the compiler to simply avoid any copying or moving at all when an object is returned, instead just using it directly on the stack where it was returned (see http://en.wikipedia.org/wiki/Return_value_optimization). No constructor is called at all.
Copied*. Unless you overload the assignment operator. Also, Structs and Classes in C++ are the same in this respect, their copy behaviour does not differ as it does in c#.
If you want to dive deep into C++ you can also look up the move operator, but it is generally best to ignore that for beginners.
C++ does not have garbage collection, and gives more control over memory management. If you want behaviour similar to c# references, you can use pointers. If you use pointers, you should use them with smart pointers (What is a smart pointer and when should I use one?).
* Keep in mind, if the struct stores a pointer, the pointer in a copied struct will point to the same location. If the object in that location is changed, both structs' pointers will see the changed object.
P.S: I assume you come from a c# background based on the vocabulary in your question.
It seems that every time I add an object to the vector m_test, the destructor method is called. Am I missing something? How can I prevent this from happening?
class TEST
{
public:
TEST();
~TEST();
int * x;
};
TEST::TEST()
{
}
TEST::~TEST()
{
... it is called every time I push_back something to the vector ...
delete x;
}
vector<TEST> m_test;
for (unsigned int i=0; i<5; i++)
{
m_test.push_back(TEST());
}
The problem here is that you're violating the Rule of Three. Your class has a destructor so you need a copy-constructor and an assignment operator, too. Alternatively, you could not allow your class to be copied (for example by making T(T const&) and T& operator=(T const&) private, or by deriving from boost::noncopyable), and then resize the vector instead of using push_back.
In the first case, you can just push_back your class as you usually would. In the second, the syntax would be something like
std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.
Not doing either of these things is a bad idea, as you are very likely to run into double deletion issues at some point -- even if you think you'll never copy or assign a TEST where x != nullptr, it's much safer to explicitly forbid it.
By the way, if you have member pointers that should be deleted when an object goes out of scope, consider using smart pointers like scoped_ptr, unique_ptr and shared_ptr (and maybe auto_ptr if you're unable to use Boost or C++11).
It's not called when you push_back, it's called when the temporary is destroyed.
To fix it in your example:
TEST test;
for (int i = 0; i < 5; ++i)
{
m_test.push_back(test);
}
Should only call it once.
Your code is creating a temporary TEST within the loop, using it in push_back, then that temporary is going out of scope when the loop ends/repeats and getting destroyed. That occurs exactly as it should, since the temporary TEST needs cleaned up.
If you want to avoid that, you need to do anything else but make a temporary object for each push. One potential solution is to:
vector<TEST> m_test(5); // Note reserving space in the vector for 5 objects
std::fill(m_test.begin(), m_test.end(), TEST()); // Fill the vector with the default ctor
Depending on how your STL is optimized, this may not need to make multiple copies.
You may also be able to get better handling if you implement a copy constructor in your TEST class, like:
TEST::TEST(const TEST & other)
{
x = new int(*other.x); // Not entirely safe, but the simplest copy ctor for this example.
}
Whether this is appropriate, or how you handle it, depends on your class and its needs, but you should typically have a copy constructor when you have defined your own regular constructor and destructor (otherwise the compiler will generate one, and in this case, it will result in copied and hanging pointers to x).
To avoid destruction of a temporary and to avoid copy constructors, consider using vector::resize or vector::emplace_back. Here's an example using emplace_back:
vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ )
{
m_test.emplace_back();
}
The vector element will be constructed in-place without the need to copy. When vt is destroyed, each vector element is automatically destroyed.
c++0x is required (use -std=c++0x with gnu). #include <vector> is of course also required.
If a default constructor is not used (for example, if the TEST::x was a reference instead of a pointer), simply add arguements to the call to emplace_back() as follows:
class TEST
{
public:
TEST( int & arg) : x(arg) {;} // no default constructor
int & x; // reference instead of a pointer.
};
. . .
int someInt;
vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ ) {
m_test.emplace_back( someInt ); // TEST constructor args added here.
}
The reserve() shown is optional but insures that sufficient space is available before beginning to construct vector elements.
vector.push_back() copies the given object into its storage area. The temporary object you're constructing in the push_back() call is destroyed immediately after being copied, and that's what you're seeing. Some compilers may be able to optimize this copy away, but yours apparently can't.
In m_test.push_back(TEST());, TEST() will create an temporary variable. After the vector copy it to its own memory, the temporary variable is destructed.
You may do like this:
vector<TEST> m_test(5, TEST());
The destructor is not only being called for the temporary variable.
The destructor will also get called when the capacity of the vector changes.
This happens often on very small vectors, less so on large vectors.
This causes:
A new allocation of memory (size based on a growth metric, not just size+1)
Copy of the old elements into the new allocation
Destruction of the elements in the old vector
Freeing of the old vector memory.
Copy construction of the new item onto the end of the new new vector.
See the third answer here:
Destructor is called when I push_back to the vector
If I create an object on the stack and push it into a list, then the object loses scope (outside of the for loop in the example below) will the object still exist in the list? If the list still holds the object, is that data now invalid/possibly corrupt?
Please let me know, and please explain the reasoning..
Thanks,
jbu
class SomeObject{
public:
AnotherObject x;
}
//And then...
void someMethod()
{
std::list<SomeObject> my_list;
for(int i = 0; i < SOME_NUMBER; i++)
{
SomeObject tmp;
my_list.push_back(tmp);
//after the for loop iteration, tmp loses scope
}
my_list.front(); //at this point will my_list be full of valid SomeObjects or will the SomeObjects no longer be valid, even if they still point to dirty data
}
EDIT: so what if it were a std::list<SomeObject*> my_list; instead of list...in that case would it be invalid?
The standard containers make a copy of the object so the list is still ok in your example.
All containers make a copy of what they store. It's a requirement that an object be copy-constructible and assignable, if it is to be used in a container.
So yes, vector, list, etc. all make a copy of your object.
An even shorter example:
struct foo {};
std::vector<foo> v;
v.push_back(foo());
// makes a copy of the temporary, which dies at the semicolon.
If it didn't make a copy, the above code would be bad.
The following code is not ok:
struct foo {};
std::vector<foo*> v;
{
foo f;
v.push_back(&f); // fine, but...
} // ...now f stops existing and...
v.front(); // ...points to a non-existent object.
Yes, it's valid. push_back makes a copy.
With all STL containers (lists, vectors, maps, everything), the containers make a copy of what you add to the containers so, so long as what you add isn't a pointer or reference, you're safe.
If you write your own containers though, you have to be careful how you do things, since there's nothing stopping you from writing a type of container that stores references -- it would just be a nasty surprise to anyone that thought it worked like a standard container.