#include <iostream>
#include<vector>
using namespace std;
class test{
public:
test(){
cout<<"constructor called"<<endl;
}
test(const test& obj){
cout<<"copy constructor called"<<endl;
}
test(test&& obj){
cout<<"Move constructor called"<<endl;
}
};
int main()
{
vector<test> vec;
vec.emplace_back(test());
return 0;
}
When i run above program I expected emplace_back to create object in vector in place.Thus "constructor called" should have been output since emplace_back would avoid creating temporary object.
But the output is:
constructor called
Move constructor called
Here, temporary object is created just like push_back. Please explain.
emplace_back doesn't construct temporaries, but you constructed a temporary object explicitly by test(), then the new element is added to the vector from the temporary by the move constructor.
You can just
vec.emplace_back();
With emplace_back(test()) you already created an object outside of emplace_back and it has a move constructor so it is move-constructed. So you should call it without any argument for this case. Then you will not see any copy/move constructor calls.
vec.emplace_back(); // Will create a test object with constructor `test()` internally
To further understand, if your test class have more constructors, you can give emplace_back with those constructors. For example,
class test {
...
test(int a, int b);
test(const char* c);
};
And you can do this.
vec.emplace_back(1, 2);
vec.emplace_back("abcd");
This does not create redundant object which is cannot be done with push_back.
With emplace_back, the method already knows what class type that you're adding to your vector (you name it when initialising the vector), so the input arguments for emplace_back is only the arguments for the constructor that you want to call (typically you want to avoid the copy constructor, whose argument is an object of the same class):
struct A
{
A (int a, int b, int c)
{
// do something
}
A (const A & other)
{
//do something else
}
};
std::vector<A> array;
array . emplace_back (1, 2, 3);
// the above finds the constructor with these input arguments
// makes the new object within the vector - no copy
A obj (4, 5, 6);
array . emplace_back ( obj );
// the above looks for the constructor with this object (A)
// it finds a constructor (the copy constructor) and copies
array . emplace_back ( A (1,2,3) );
// the above first processes the inner part: making a new A object
// then searches for a constructor with that argument (an object A)
// in this case that's the copy constructor
In your case you were wanting to call a constructor with no arguments. This is why you want to use emplace_back() with no arguments to use this vector method correctly.
Related
I'm studying to understand class constructor and destructor.
I have written a small console code to add one class instance in to a vector. All is nice and dandy, but what I fail to understand is, that adding one Object in to the vector triggers destructor twice. Why does this happen?
If I don't add any object, the vector doesn't trigger constructor or destructor on its own, so why it happens twice?
Can anyone explain why this happens?
#include <cstdio>
#include <vector>
class Test
{
private:
int value;
public:
Test()
{
printf("\nClass constructor triggered.");
};
~Test()
{
printf("\nClass desctructor triggered.");
}
};
int main()
{
std::vector<Test> container;
container.push_back( Test() );
return 0;
}
UPDATE:
I added some more information to the class so that I get more specific output, however now I noticed that with each addition to the vector the move-construction and destructor calls increase. Are the amount of these calls tied to the amount of objects within the vector or what is happening?
Am I having a leak? Sorry if too stupid questions.
Below is the added code:
#include <cstdio>
#include <vector>
class Test
{
private:
int value;
public:
// Constructor
Test(int v=0)
{
value = v;
printf("\n\n%i", value);
printf("\nClass constructor triggered.");
};
// Copy-move constructor
Test(Test&&)
{
printf("\nClass move-constructor triggered.");
};
// Destructor
~Test()
{
value = 0;
printf("\nClass desctructor triggered.");
}
};
int main()
{
std::vector<Test> container;
container.push_back( Test(1) );
container.push_back( Test(2) );
container.push_back( Test(3) );
container.push_back( Test(4) );
printf("\n\nPushback complete!");
return 0;
}
Your vector contains a copy of the object you add to it through push_back(). The first destructor invocation is caused by the temporary you create being destroyed at the end of the full expression containing the call to push_back(). The second destructor is caused by the copy inside the vector being destroyed when the vector itself is destroyed.
You can convince yourself by adding a diagnostic to main():
int main()
{
std::vector<Test> container;
container.push_back( Test() );
printf("\nThis is before the vector is destroyed...");
return 0;
}
You can observe the output in this live example.
The copy which your vector contains is created by invoking the automatically-generated move constructor for your class (rather than using default construction), which is why you don't see a corresponding construction diagnostic.
If you defined your own move constructor (or copy constructor, as shown below) to emit a diagnostic, the output would be closer to what you'd expect:
Test(Test const&)
{
printf("\nCopy construction triggered.");
};
Again, live example.
Because you don't print every constructor invocation, you're missing out on move-constructor call. Your class, apart from the default constructor you've provided, has also implicitly generated move and copy constructors.
The vector stores a value, and that value has to be initialized in some way. Typically, this happens either via a move c-tor or copy c-tor, altough an object might also be created directly inside of the vector using e.g. emplace_back.
Try adding this:
Test(Test&&)
{
printf("\nClass move constructor triggered.");
};
to your class, it should change the output to something that makes more sense (I've also added a print at the end of main):
Live On Coliru
Class constructor triggered.
Class moveconstructor triggered.
Class desctructor triggered.
Out of main scope.
Class desctructor triggered.
The first destructor call destroys moved-out "empty" instance of your class, while the second one fires when the vector itself is destroyed.
The push_back() does not trigger any destructor (in this case).
The two calls to Test's destructor are:
1 - Because you pass a temporary to push_back(), so that object get destroyed when push_back() is done
2 - when the program end, so the vector get destroyed and so it is it's content
For the sake of simplicity, let's assume you are working with C++03, and move semantics are not available yet.
Add copy constructor to see that it is also triggered
Test(const Test&)
{
printf("\nClass copy constructor triggered.");
};
Output
Class constructor triggered.
Class copy constructor triggered.
Class destructor triggered.
Class destructor triggered.
So, there are two objects constructed/destructed.
Roughly speaking, your code is equal to
int main()
{
std::vector<Test> container;
Test test; // first object created
container.push_back(test); // second object created by copying
return 0;
}
I got the follwing block of code:
#include <vector>
#include <iostream>
struct TestStruct {
bool wasCreated;
TestStruct() {
std::cout << "Default Constructor" << std::endl;
wasCreated = false;
}
~TestStruct() {
if (wasCreated) {
DoImportantStuff();
}
}
void Create() {
wasCreated = true;
}
// delete all copy stuff
TestStruct(const TestStruct&) = delete;
TestStruct& operator=(const TestStruct&) = delete;
// implement only move assignment & ctor
TestStruct(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
}
TestStruct& operator=(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
return *this;
}
// very important stuff
void DoImportantStuff() {
std::cout << "Do Important Stuff" << std::endl;
}
};
int main() {
std::vector<TestStruct> testVector;
testVector.emplace_back(TestStruct());
testVector.emplace_back(TestStruct());
std::cin.get();
}
This code leads to the output:
Default Constructor
Do Important Stuff
Default Constructor
Do Important Stuff
Do Important Stuff
Basicly I wanted to write a class, which owns memory but allocates this memory only when I call Create(). To avoid memory leaks and to avoid deleting not allocated memory I introduced wasCreated which will be only true when i call Create(). Every TestStruct should be saved in one vector. So in implemented move assigment & ctor and deleted both copy assigment & ctor.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory. Why is so and how do get the vector to call the default constructor on memory allocation? Do I need my own allocator?
Your problem is that your move constructor is implemented incorrectly. It swaps wasCreated between the newly created object and the one being moved from, but the variable in the newly created object has not been initialized yet (a default-constructed bool has an unknown value). So your temporary objects created with TestStruct() receive an uninitialized bool, which happens to be true in your case, hence the calls to DoImportantStuff() in their destructors.
So the move constructor should look something like this:
// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
other.wasCreated = false;
}
(You have moved ownership to the newly created object, the old one doesn't own anything anymore.)
Don't confuse the assignment operator with the constructor; they do different things. The assignment operator deals with two objects that are both already constructed; in the case of the constructor, the object being constructed is, well..., not constructed yet, so it doesn't have a valid state.
By the way, emplace_back() is pointless the way you're using it. Its purpose is to forward its arguments directly to the constructor of the object inside the vector. Since you have a default constructor (no arguments), the call should be:
testVector.emplace_back();
This will default-construct the TestStruct in place.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory.
A default-constructed vector has zero size, so there are no objects to construct.
If you want the vector to default-construct some objects, resize it.
I want to use vector::emplace to default construct a non-copyable and non-assignable object and then use specific methods on the object using an iterator to the newly created object. Note that there are no parameterized constructors of the class just the default constructor. A simple example is:
#include <iostream>
#include <vector>
using namespace std;
class Test {
public:
Test() {}
private:
Test(const Test&) = delete; // To make clas un-copyable.
Test& operator=(const Test&) = delete;
int a_;
};
int main() {
vector<Test> test_vec;
test_vec.emplace_back(); // <---- fails
return 0;
}
vector::emplace() constructs a new object but requires arguments to a non-default constructor. vector::emplace_back() will construct at the end of the vector.
Is there a way to emplace with default construction. Is there a way to use piecewise construction or default forwarding perhaps using std::piecewise_construct as there is for maps? For example, in the case of maps, we can use:
std::map<int,Test> obj_map;
int val = 10;
obj_map.emplace(std::piecewise_construct,
std::forward_as_tuple(val),
std::forward_as_tuple());
Is there something similar for vectors?
vector::emplace_back() will construct at the end of the vector but also require arguments.
Parameter packs can be empty. Thus the variadic template emplace_back can be called without arguments; I.e.
vector<VeryLimitedClass> vec;
vec.emplace_back();
Is valid code that initializes an object of type VeryLimitedClass through its default constructor and "emplaces" it at the back of vec.
As pointed out by #dyp and #Casey in the comments, std::emplace will not work for vectors of the Test class as the class is neither movable nor copyable because "the user-declared copy constructor suppresses generation of the default move constructor" (#Casey).
To use emplace here, the class will need to be movable or copyable. We can make the class movable by explicitly defining (and defaulting) the move constructors:
public:
Test(Test&& other) = default;
Test& operator=(Test&& other) = default;
This will also implicitly make the class not-copyable "since declaring the move operations will suppress implicit generation of the copies." (#Casey)
Now we can use std::emplace_back() and then use vector::back() to call methods of the newly created object.
For map, easy:
std::map<int, Object> obj_map;
obj_map[10]; // default-constructs an object with key 10
Otherwise, what you have works too:
obj_map.emplace(std::piecewise_construct,
std::forward_as_tuple(10),
std::forward_as_tuple(args, to, construct, with));
[edit] The equivalent for vector is emplace_back:
obj_vector.emplace_back(); // default construct
obj_vector.emplace_back(args, to, std::move(construct), with); // forward these
#include <iostream>
using namespace std;
class t{
private:
int * arr;
public:
t() { arr=new int[1]; arr[0]=1;}
t(int x) {arr=new int[1]; arr[0]=x;}
t(const t &);
~t() {cout<<arr[0]<<" de"<<endl; delete [] arr;}
t & operator=(const t & t1){arr[0]=t1.arr[0];return *this;}
void print(){cout<<arr[0]<<endl;}
};
t::t(const t & t1) {arr=new int[1];arr[0]=t1.arr[0];}
int main(){
t b=5;
cout<<"hello"<<endl;
b.print();
b=3;
b.print();
return 0;
}
Why the result is
hello
5
3 de
3
3 de ?
why "t b=5;" will not call the destructor? how "t b=5" works? does it create a temp object (of class t) using constructor "t(int x)" first, then use copy constructor "t(const t &)" to create b?
if it is the case why it does not call the desctructor for the temp object?
why "t b=5;" will not call the destructor?
When you do this:
t b=5;
you get copy initialization. Semantically, the implicit converting constructor t(int) is called, and then the copy constructor t(const t&) is called to instantiate b. However, the compiler is allowed to elide the copy, which is what is happening in your case. The object is constructed in place, without need for a copy construction. This is why you do not see a destructor call. But your class still needs a copy constructor for that code to compile: copy elision is optional, and whether some code compiles should not depend on whether the compiler is performing an elision or not.
If you had said
t b(5);
then there would be a direct initialization, with no copy elision, and with only one constructor call. Your class would not require a copy constructor in for this code to compile.
Since you don't have an assignment operator taking an int, b = 3; is interpreted as
`b.operator=(t(3));`
This creates a temporary t instance, and destroys it once the assignment returns. That's what prints the first de line. Finally, at the end of main, b goes out of scope, its destructor is called and prints the second line.
Maybe a little trace from your program help you understand what is happing:
int main(){
t b=5; // as you expected, this call the constructor of your object.
cout<<"hello"<<endl;
b.print(); // as you could see, this call print() and print 5
b=3; // this is where the confusion begins. You didn't provide a way
// from your object to make an assigment from an integer, but you
// provide a way to construct an object from integer. So, your
// compiler will construct a temporary object, with 3 as parameter
// and use this object to do this assignment. Once this is a
// temporary object, it will be destructed at the end of this
// operation. That is why you are getting the message: 3 de
b.print(); // print 3 as expected
return 0; // call the destruct from the object that was assigned before
}
I'm confused about when a move constructor gets called vs a copy constructor.
I've read the following sources:
Move constructor is not getting called in C++0x
Move semantics and rvalue references in C++11
msdn
All of these sources are either overcomplicated(I just want a simple example) or only show how to write a move constructor, but not how to call it. Ive written a simple problem to be more specific:
const class noConstruct{}NoConstruct;
class a
{
private:
int *Array;
public:
a();
a(noConstruct);
a(const a&);
a& operator=(const a&);
a(a&&);
a& operator=(a&&);
~a();
};
a::a()
{
Array=new int[5]{1,2,3,4,5};
}
a::a(noConstruct Parameter)
{
Array=nullptr;
}
a::a(const a& Old): Array(Old.Array)
{
}
a& a::operator=(const a&Old)
{
delete[] Array;
Array=new int[5];
for (int i=0;i!=5;i++)
{
Array[i]=Old.Array[i];
}
return *this;
}
a::a(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
}
a& a::operator=(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
return *this;
}
a::~a()
{
delete[] Array;
}
int main()
{
a A(NoConstruct),B(NoConstruct),C;
A=C;
B=C;
}
currently A,B,and C all have different pointer values. I would like A to have a new pointer, B to have C's old pointer, and C to have a null pointer.
somewhat off topic, but If one could suggest a documentation where i could learn about these new features in detail i would be grateful and would probably not need to ask many more questions.
A move constructor is called:
when an object initializer is std::move(something)
when an object initializer is std::forward<T>(something) and T is not an lvalue reference type (useful in template programming for "perfect forwarding")
when an object initializer is a temporary and the compiler doesn't eliminate the copy/move entirely
when returning a function-local class object by value and the compiler doesn't eliminate the copy/move entirely
when throwing a function-local class object and the compiler doesn't eliminate the copy/move entirely
This is not a complete list. Note that an "object initializer" can be a function argument, if the parameter has a class type (not reference).
a RetByValue() {
a obj;
return obj; // Might call move ctor, or no ctor.
}
void TakeByValue(a);
int main() {
a a1;
a a2 = a1; // copy ctor
a a3 = std::move(a1); // move ctor
TakeByValue(std::move(a2)); // Might call move ctor, or no ctor.
a a4 = RetByValue(); // Might call move ctor, or no ctor.
a1 = RetByValue(); // Calls move assignment, a::operator=(a&&)
}
First of all, your copy constructor is broken. Both the copied from and copied to objects will point to the same Array and will both try to delete[] it when they go out of scope, resulting in undefined behavior. To fix it, make a copy of the array.
a::a(const a& Old): Array(new int[5])
{
for( size_t i = 0; i < 5; ++i ) {
Array[i] = Old.Array[i];
}
}
Now, move assignment is not being performed as you want it to be, because both assignment statements are assigning from lvalues, instead of using rvalues. For moves to be performed, you must be moving from an rvalue, or it must be a context where an lvalue can be considered to be an rvalue (such as the return statement of a function).
To get the desired effect use std::move to create an rvalue reference.
A=C; // A will now contain a copy of C
B=std::move(C); // Calls the move assignment operator
Remember that copy elision could occur. If you disable it by passing the -fno-elide-constructors flag to the compiler your constructor might get executed.
You can read about it here: https://www.geeksforgeeks.org/copy-elision-in-c/
Answers above do not give a 'natural' example when a move constructor is called. I found this way to call move constructor without std::move (and without suppressing copy elision by -fno-elide-constructors):
a foo(a a0) {
return a0; // move ctor is called
}
a a1 = foo(a());