Lifetime of objects in c++ - c++

class Entity
{
public:
int a;
Entity(int t)
:a(t)
{
std::cout << "Constructor !" << std::endl;
}
~Entity()
{
std::cout << "Destructor !" << std::endl;
}
Entity(Entity& o)
{
std::cout << "Copied !" << std::endl;
this->a = o.a;
}
};
Entity hi()
{
Entity oi(3);
return oi;
}
int main()
{
{
Entity o(1);
o = hi();
}
std::cin.get();
}
OUTPUT:
Constructor !
Constructor !
Copied !
Destructor !
Destructor !
Destructor !
I created two objects and I copied one, So three constructors and three destructors.

Your "Copied!" line in the output is coming from the copy constructor, so you're creating three objects, not just two (then you're destroying all three, as expected).
Note that a copy constructor should normally take its argument by const reference. At a guess, you may be using Microsoft's C++ compiler, which will bind a temporary to a non-const reference.
Also note that if you turn on optimization, you can probably expect to see just two constructors and two destructors, with no copy construction happening. With a new enough (C++17) compiler, that should happen even if you don't turn on optimization (copy elision has become mandatory).

This is a trivial question
Can any one explain the reason for three destructor?
when you call
o=hi();
your function is called which makes an object of type Entity , which in return calls the constructor.
This is where you get one extra constructor message
Replace your Entity(int t) contructor by this
Entity(int t)
:a(t)
{
std::cout << "Constructor created with integer "<< a << std::endl;
}
You will see which constructors were called when you run the code.

Related

Why std::move doesn't avoid a second destruction?

I know ordinary std::vector::push_back() will copy the object. I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying. But it doesn't seem to work.
Is there any way that I can construct an object before push_back() and move it into a vector perfectly?
#include <bits/stdc++.h>
using namespace std;
class A {
public:
A() { std::cout << "construct" << this << '\n'; }
A(A&&) noexcept { std::cout << "move" << this << "\n"; }
A(const A&) = delete;
~A() { std::cout << "destruct" << this << '\n'; }
};
std::vector<A> as;
void add(A&& a) {
std::cout << "add 1\n";
as.push_back(std::move(a));
std::cout << "add 2\n";
}
int main() {
add(A());
std::cout << "main2\n";
return 0;
}
Output:
construct0x16d20b1fb
add 1
move0x151e068b0
add 2
destruct0x16d20b1fb
main2
destruct0x151e068b0
I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying.
Using Move constructor perverts copying but doesn't prevent creating new objects, you are creating an inline object with default constructor "cout : construct0x16d20b1fb" and then from that object's data your going to create a 'NEW' object and calling move constructor will
transform the ownership of the object's data/resources to the new object that is being 'Constructed' so that explain the "cout : move0x151e068b0" then the line is finished so your inline object is destroyed "cout " destruct0x16d20b1fb" then your program finishes "cout : destruct0x151e068b0" your object that made via move constructor is destroyed.
you are expecting the behavior of pointers from your vector of "Objects" which is supposed to hold actual objects not pointer to other objects so it needs to containt objects and each of objects that are in that vector has a different address, unless you create your object and use a vector pointers to objects.
By the way std::move is but a cast, it casts to rvalue references so when you are capturing with rvalue reference there's no need to cast it again, you should be using it like this:
A a_object1;
vector.push_back(std::move(a_object1));
and it will use the move constructor. although in this case it will cast it implicitly because you are capturing only by rvalue reference in add function unless you add an overload to this function that also takes reference there's no need.

Understanding the reasoning between copy/move constructors and operators

I am trying to get the grasp of rvalue references and move semantics with a simple self-made example but I can't understand a specific part. I have created the following class:
class A {
public:
A(int a) {
cout << "Def constructor" << endl;
}
A(const A& var) {
cout << "Copy constructor" << endl;
}
A(A&& var) {
cout << "Move constructor" << endl;
}
A& operator=(const A& var) {
cout << "Copy Assignment" << endl;
return *this;
}
A& operator=(A&& var) {
cout << "Move Assignment" << endl;
return *this;
}
};
I tried the following experiments to see if I can predict how the constructors/operators are going to be called:
A a1(1) - The default constructor is going to be called.
PREDICTED.
A a2 = a1 - The copy constructor is going to be called. PREDICTED.
a1 = a2 - The copy assignment operator is going to be called.
PREDICTED.
Now, I created a simple function that just returns an A object.
A helper() {
return A(1);
}
A a3 = helper() - The default constructor is going to be called in
order to create the object that the helper returns. The move
constructor is not going to be called due to RVO. PREDICTED.
a3 = helper() - The default constructor is going to be called in
order to create the object that the helper returns. Then, the move
assignment operator is going to be called. PREDICTED.
Now comes the part I don't understand. I created another function that is completely pointless. It takes an A object by value and it just returns it.
A helper_alt(A a) {
return a;
}
A a4 = helper_alt(a1) - This will call the copy constructor, to
actually copy the object a1 in the function and then the move
constructor. PREDICTED.
a4 = helper_alt(a1) - This will call the copy constructor, to
actually copy the object a1 in the function and then I thought that
the move assignment operator is going to be called BUT as I saw,
first, the move constructor is called and then the move assignment
operator is called. HAVE NO IDEA.
Please, if any of what I said is wrong or you feel I might have not understood something, feel free to correct me.
My actual question: In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator?
Congratulations, you found a core issue of C++!
There are still a lot of discussions around the behavior you see with your example code.
There are suggestions like:
A&& helper_alt(A a) {
std::cout << ".." << std::endl;
return std::move(a);
}
This will do what you want, simply use the move assignment but emits a warning from g++ "warning: reference to local variable 'a' returned", even if the variable goes immediately out of scope.
Already other people found that problem and this is already made a c++ standard language core issue
Interestingly the issue was already found in 2010 but not solved until now...
To give you an answer to your question "In the last case, why is the move constructor being called and then the move assignment operator, instead of just the move assignment operator?" is, that also C++ committee does not have an answer until now. To be precise, there is a proposed solution and this one is accepted but until now not part of the language.
From: Comment Status
Amend paragraph 34 to explicitly exclude function parameters from copy elision. Amend paragraph 35 to include function parameters as eligible for move-construction.
consider the below example. I have compiled the sample code using -fno-elide-constructors flag to prevent RVO optimizations:
g++ -fno-elide-constructors -o test test.cpp
#include<iostream>
using namespace std;
class A {
public:
A(int a) {
cout << "Def constructor" << endl;
}
A(const A& var) {
cout << "Copy constructor" << endl;
}
A(A&& var) {
cout << "Move constructor" << endl;
}
A& operator=(const A& var) {
cout << "Copy Assignment" << endl;
return *this;
}
A& operator=(A&& var) {
cout << "Move Assignment" << endl;
return *this;
}
};
A a_global(1);
A helper_alt(A a) {
return a;
}
A helper_a_local(A a) {
A x(1);
return x;
}
A helper_a_global(A a) {
return a_global;
}
int main(){
A a1(1);
A a4(4);
std::cout << "================= helper_alt(a1) ==================" << std::endl;
a4 = helper_alt(a1);
std::cout << "=============== helper_a_local() ================" << std::endl;
a4 = helper_a_local(a1);
std::cout << "=============== helper_a_global() ================" << std::endl;
a4 = helper_a_global(a1);
return 0;
}
This will result in the below output:
Def constructor
Def constructor
Def constructor
================= helper_alt(a1) ==================
Copy constructor
Move constructor
Move Assignment
=============== helper_a_local() ================
Copy constructor
Def constructor
Move constructor
Move Assignment
=============== helper_a_global() ================
Copy constructor
Copy constructor
Move Assignment
In simple words, C++ constructs a new temporary object (rvalue) when the return type is not a reference, which results in calling Move or Copy constructor depending on the value category and the lifetime of the returned object.
Anyway, I think the logic behind calling the constructor is that you are not working with reference, and returned identity should be construed first, either by copy or move constructor, depending on the returned value category or lifetime of the return object. As another example:
A helper_move_vs_copy(A a) {
// Call the Copy Constructor
A b = a;
// Call the Move Constructor, Due to the end of 'a' lifetime
return a;
}
int main(){
A a1(1);
A a2(4);
std::cout << "=============== helper_move_vs_copy() ================" << std::endl;
helper_move_vs_copy(a1);
return 0;
}
which outputs:
Def constructor
Def constructor
=============== helper_move_vs_copy() ================
Copy constructor
Copy constructor
Move constructor
From cppreference:
an xvalue (an “eXpiring” value) is a glvalue that denotes an object whose resources can be reused;
At last, it is the job of RVO to decrease unnecessary moves and copies by optimization of the code, which can even result in an optimized binary for basic programmers!

Copy constructor and returning passed argument

I'm reading Prata's C++ book, and when talking about copy constructors, it says that this constructor is invoked when:
Initializing a class object to the a class object of the same type.
Passing an object by value to a function.
Returning an object by value from a function.
Let say that we are working with a Vector class.
For understanding sakes, throughout the examples in the current chapter we included in the constructors/destructor definitions string outputs, to indicate which and when each of them is called.
For instance, if we have
int main()
{
Vector v1; // print "Default constructor called"
Vector v2(9, 5); // print "Constructor called"
Vector v3 = v1; // print "Copy Constructor called"
return 0;
}
And Destructor called would be printed in this case 3 times, when exiting main().
In order to check the 3 points above I've been playing with a dumb_display() function, changing the type of the formal parameter/return value. In doing so, I got confused about what is indeed happening under the hood.
Vector dumb_display(Vector v)
{
Vector test(45, 67);
cout << "In dumb_display() function" << endl;
cout << v << endl;
return v;
}
Here:
Every time we return by value the passed argument as in the above function (argument either passed by value or reference) the copy constructor gets called.
It makes sense. It satisfies point 3.
Every time we return an object defined in the function's body (e.g., changing return v; by return test;), the copy constructor isn't called.
Point 3 isn't satisfied.
I'm having a hard time trying to understand this behaviour.
I don't know whether this is correct, but I think (since an automatic storage duration object is created once for the duration of the function call) once test is created it, hasn't have to be created again, because the object "is already there". This brings the question:
Why does returning the passed argument call the copy constructor twice? Why does the same object have to be created twice for the duration of the call to the function?
#include <vector>
#include <type_traits>
#include <tuple>
#include <iostream>
using namespace std;
struct S {
S(){
cout << "default constructor" << endl;
}
S(S const &) {
cout << "copy constructor" << endl;
}
S(S &&) {
cout << "move constructor" << endl;
}
S & operator=(S const &) {
cout << "copy assignment" << endl;
return *this;
}
S & operator=(S &&) {
cout << "move assignment" << endl;
return *this;
}
};
S f() {
S s2;
cout << "In f()" << endl;
return s2;
}
S f2(S s) {
cout << "In f2()" << endl;
return s;
}
int main() {
cout << "about to call f" << endl;
S s2 = f();
(void)s2;
cout << endl << "about to call f2" << endl;
S s3 = f2(s2);
(void)s3;
}
results in:
about to call f
default constructor
In f()
about to call f2
copy constructor
In f2()
move constructor
In f(), the object is default constructed and return value optimization is used to actually construct it in place where it will actually end up -- in the s2 variable in main. No copy/move constructors are called.
In f2(), a copy is made for the input parameter for the function. That value is then moved into the variable s3 in main, again with return return value optimization.
live: https://wandbox.org/permlink/kvBHBJytaIuPj0YN
If you turn off return value optimization, you will see the results that you would expect from what your book says:
live: https://wandbox.org/permlink/BaysuTYJjlJmMGf6
Here's the same two examples without move operators if that's confusing you:
live: https://wandbox.org/permlink/c0brlus92psJtTCf
and without return value optimization:
live: https://wandbox.org/permlink/XSMaBnKTz2aZwgOm
it's the same number of constructor calls, just using the (potentially slower) copy constructor instead of the move constructor.
The copy constructor is called twice because it is first copied from the function into the temperary value (which is represented by the function call and is what the returned value is, then copied into the variable, requiring two copies. Since this is not very efficient, there is also a "move" constructor, which is only needed once.

Too many destructors called on template classes (N)RVO optimization

I'm trying to write own Smart Pointers (C++11) and stacks with one problem, that can be explained by next example:
#include <iostream>
template<typename T_Type>
class TestTemplateClass {
private:
T_Type _state;
public:
TestTemplateClass() : _state() {
std::cout << "Default constructor" << std::endl;
}
TestTemplateClass(int inState) : _state(inState) {
std::cout << "State constructor" << std::endl;
}
template<typename T_OtherType>
TestTemplateClass(const TestTemplateClass<T_OtherType> &inValue) {
std::cout << "Template-copy constructor" << std::endl;
}
template<typename T_OtherType>
void operator = (const TestTemplateClass<T_OtherType> &inValue) {
std::cout << "Operator" << std::endl;
}
~TestTemplateClass() {
std::cout << "Destructor" << std::endl;
}
};
TestTemplateClass<int> createFunction() {
return TestTemplateClass<int>();
}
int main() {
TestTemplateClass<int> theReference = createFunction();
std::cout << "Finished" << std::endl;
return 0;
}
output:
Default constructor
Destructor
Destructor
Finished
Destructor
As you can see, there are to many destructors here. In my mind, it's some problem with interaction between copy elision and template-constructor, but I don't know what may be the reason of such bug. I tried to fix the problem by adding explicit copy-constructor and force compiler use my template-constructor:
// After TestTemplateClass(int inState), but it's not important
explicit TestTemplateClass(const OwnType &inValue) {
std::cout << "Copy constructor" << std::endl;
}
got next output:
Default constructor
Template-copy constructor
Destructor
Template-copy constructor
Destructor
Finished
Destructor
Here all looks good, but it doesn't look like a clean solution. Are there better alternatives?
(N)RVO can never introduce a discrepancy between the number of constructor and destructor calls. It's designed to make that principally impossible.
The problem is with your code. According to the rules of the language, a constructor template is never used to produce a copy constructor. The copy constructor is never a template, period.
So your class template does not actually declare a copy constructor, hence the compiler generates the default one (which of course doesn't print anything). If you need any special processing in the copy constructor, you must always declare it manually. A template will never be used to instantiate one.
Your experiment suggests there isn't a bug at all: the first version simply used the copy constructor which doesn't print anything, and the second version uses a different constructor instead because you effectively disabled it.
(it also looks like whatever compiler and options you're using doesn't do RVO)

Why is there no memory leak here

I was trying to answer this question, so I decided to create the following simple test case so that the OP could see by himself the memory leak.
#include<iostream>
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo)
{
}
int main()
{
processMyObject(*new MyObject());
return 0;
}
I compiled it :
g++ test.cpp -o test
And then, I saw an unexpected output :
creation of my object
destruction of my object
I have absolutly no idea of what is happening here. Could anyone explain to me ?
PS: I used g++ 4.6.3
Since you pass an object by value to the function, you incurr a copy or move-copy construction. But you are not keeping track of that with your primitive memory leak checker. You could provide your own copy constructor, and then you will see two objects are being created, and only one is being destroyed:
#include<iostream>
class MyObject
{
public:
MyObject() {std::cout << "creation of my object" << std::endl;}
MyObject(const MyObject&) {std::cout << "copy creation of my object" << std::endl;}
~MyObject() {std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo) {}
int main()
{
processMyObject(*new MyObject());
}
Output:
creation of my object
copy creation of my object
destruction of my object
Because you're taking the MyObject by value.
Thus there is a destruction. But it is the destruction of the foo argument at the end of processMyObject.
The *new does actually still leak in this case.
EDIT: As pointed out by juanchopanza, you need to also print a statement in the copy constructor and in the move constructor as well.
What happens in your code
You construct an object and get information about it (creation of my object)
You pass it to function - copy constructor fires, but does not report anything
The copy is destroyed - you get information about it (destruction of my object)
The original instance leaks despite fact, that you don't have any information about it.
How to see it?
Simply report pointers to this during construction and destruction (quick'n'dirty, please don't complain):
class MyObject
{
public:
MyObject(){std::cout << "creation of my object (" << (int)this << ")" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object (" << (int)this << ")" << std::endl;}
};
Result:
creation of my object (165437448)
destruction of my object (-1076708692)
As you see, destroyed object is different than created one.
How to "fix" it to show the leak?
The simplest way to "fix" your code is to pass object by pointer:
#include<iostream>
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject * foo)
{
}
int main()
{
processMyObject(new MyObject());
return 0;
}
Another option is to report copy ctors and move ctors as well:
class MyObject
{
public:
MyObject(){std::cout << "creation of my object" << std::endl;}
MyObject(const MyObject & obj) { std::cout << "copy-ctor" << std::endl; }
MyObject(MyObject && obj) { std::cout << "move-ctor" << std::endl; }
virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
There actually is a memory leak. Just because your object was destroyed, doesn't mean that you deleted the resources you acquired with new. You have to explicitly use delete.
EDIT
So here's what's happening:
You are calling the default constructor on the fly, and passing it to the function call. This prints the first message.
As part of the function call, the object is passing to processMyObject(), creating a new object in that scope using the copy constructor, which has been implicitly defined by the compiler.
When that object (in processMyObject()) goes out of scope, its destructor is called, printing the second message.
So, the instance printing the first message is different from that printing the second one.
Hope that clears things up.