Consider the following snippet of c++ and the output below it.
#include <iostream>
using namespace std;
class One {
public:
One(int num);
One();
~One();
private:
int number;
};
One::One(int num) {
number = num;
cout << "One constructor number = " << number << endl;
}
One::One() {
number = 0;
cout << "default One constructor\n";
}
One::~One() {
cout << "One destructor. number = " << number << endl;
number = 0;
}
int main() {
One uno;
uno = One(2);
return 0;
}
default One constructor
One constructor number = 2
One destructor. number = 2
One destructor. number = 2
Notice the replication of the last line. I understand (& hate) why the default constructor is called by the first line in main, but the destructor for that instance is never called. Instead the destructor for the second instance is implicitly called twice. Why? And how is the variable 'number' able to persist at number=2 ? The destructor set it to 0. It's like the garbage collector is trying to delete the instance created by the default constructor but hitting an old copy of the 2nd. This is a trivial example but it's a real problem when it comes time to delete pointers.
One uno; // Create a default One instance - default constructor called.
uno = One(2); // Create a temporary One instance - number constructor called and prints 2.
// Assign temporary to uno - uno now has the number 2.
// Destroy temporary One instance - destructor called and prints 2.
return 0;
// uno destroyed. It has the number 2, so this also prints 2.
Or, in terms of the output you saw:
default One constructor // from uno construction
One constructor number = 2 // from temporary One(2) construction
One destructor. number = 2 // from temporary One(2) destruction
One destructor. number = 2 // from uno destruction (since number has changed)
Related
#include <iostream>
#include <vector>
#include <algorithm>
class my {
public:
my() {
counter++;
std::cout << "class constructor" << counter << " \n";}
~my() {
std::cout << "class destructor" << counter << " \n";
counter--;
}
static inline int counter = 0;
};
int main()
{
my v1;
std::vector<my> my_vec;
my * p = new my();
my_vec.push_back(std::move(*p));
my_vec.push_back(std::move(v1));
}
simply example, however I do not understand what I am doing wrong, in result I get 2 extra destructor called than I expect (expect 2). Could some one explain it?
results:
class constructor1
class constructor2
class destructor2
class destructor1
class destructor0
class destructor-1
Analyzing the program step-by-step:
my v1;
One Instance is created, constructor is called.
my * p = new my();
Another instance is created, constructor is called.
my_vec.push_back(std::move(*p));
A copy of the second instance is inserted into the vector; the implicitly defined move-constructor is called (which just copies; no output is printed).
my_vec.push_back(std::move(v1));
The vector allocates new storage for 2 instances, copies the previously stored instance into the new storage (invoking the implicitly defined move-constructor, which just does copying, still no output for this), and invokes the destructor for the instance in the old storage (so first destructor output is printed).
Then, the vector goes out of scope, so its two contained elements get destroyed (so, 2 destructor calls). Then, v1 goes out of scope, printing the 4th destructor call. The instance p is leaked, i.e. never destroyed (memory leak).
Please see inline ...
#include <iostream>
#include <vector>
class my {
public:
my() {
counter++;
std::cout << "class constructor" << counter << " \n";
std::cout << "Object Address : " << this << std::endl;
}
~my() {
std::cout << "class destructor" << counter << " \n";
std::cout << "Object Address : " << this << std::endl;
counter--;
}
static inline int counter = 0;
};
int main()
{
my v1; /* 1. Object on stack (constructor called) */
std::vector<my> my_vec;
my * p = new my(); /* 2. Object created on heap (constructor called) */
my_vec.push_back(std::move(*p));
my_vec.push_back(std::move(v1));
}
Output is:
class constructor 1 Address : 0x7ffee1488760
class constructor 2 Address : 0x7f9f47400350
class destructor 2 Address : 0x7f9f474026e0
class destructor 1 Address : 0x7f9f474026f1
class destructor 0 Address : 0x7f9f474026f0
class destructor -1 Address : 0x7ffee1488760
Object on the stack called destructor as soon as it goes out of the scope i.e. Scope of the object on stack is limited to the code block. In this case block end when main exits.
But the object on heap (new) is a potential leak, had this being inside while loop would have consumed memory and eventually crashed. For each new you need to explicitly called delete, which means you have to call its destructor. Thanks to stack it does that for us but not heap, and c++ also doesn't have garbage collector.
std::move is a copy operation and hence no constructor is called. details here.
My C++ Programm always calls too more constructors than i intended to. It should create an edge, which then automatically creates two nodes by the string-input of the overloaded edge-constructor.
But it first calls the default-constructor of the node objects and then the overloaded self-defined constructor. The destructors do not delete the default nodes immediately. That causes an error in my program.
The problem is that the program should count the amount of objects and allocate an appropriate ID related to the amount of objects.
Compiler-Output
Default-Constructor
Default-Constructor
Overload-Constructor
ID: 1 numInstances: 2
Destructor
Overload-Constructor
ID: 2 numInstances: 1
Destructor
Edge: -> Node_0002
Destructor
Destructor
Program ended with exit code: 0
Here is a snippet for you to see the code which most likely causes the error:
main.cpp
int main() {
Edge e1 = Edge("1", "2");
std::cout << "Edge: " << e1.toString() << endl;
return 0;
}
node.hpp
double Node::numInstances = 0;
Node::Node()
{
numInstances++;
cout << "Default-Constructor" << endl;
double idNumber = numInstances;
m_id = setUpIdString(idNumber);
}
Node::Node(string id)
{
double idNumber = getNumberFromString(id);
cout << "Overload-Constructor" << endl;
cout << "ID: " << idNumber << " numInstances: " << numInstances << endl;
if (idNumber > numInstances) {
numInstances++;
m_id = setUpIdString(idNumber);
}
}
Node::~Node()
{
numInstances--;
cout << "Destructor" << endl;
}
edge.cpp
Edge::Edge(string src, string dst)
{
m_srcNode = Node(src);
m_dstNode = Node(dst);
}
EDIT:
node.hpp
class Node
{
public:
Node();
Node(string id);
~Node();
string getId();
private:
string m_id;
static double numInstances;
};
edge.hpp
class Edge
{
public:
Edge(Node& rSrc, Node& rDst);
Edge(string src, string dst);
string toString();
Node& getSrcNode();
Node& getDstNode();
private:
Node m_srcNode;
Node m_dstNode;
};
A constructor is not like other functions in C++. A constructor's job is to initialize an object. In order to ensure the object gets initialized in a sensible way, all of the member objects (and base objects) need to be initialized. *This happens before the opening brace of the constructor body, so that everything is in a sensible state when you're in the constructor body.
To make sure this happens in the way you want, you can use an initializer list (note that this term also refers to something else when initializing various containers; if you've heard the term before in relation to that, it's not what I'm discussing here). After the function signature, you put a colon, followed by each member of your class (in the same order they're declared in the class) and how you want to initialize it. For example, if you have the following struct
struct A {
int i;
char c;
std::string s;
A();
};
you can declare define your constructor as
A::A() : i{17}, c{'q'}, s{"Hello, mrb! Welcome to Stack Overflow"}
{
// Nothing to do in the body of the constructor
}
That way, an A object's members are initialized to 17, 'q', and a greeting before the start of the function, and are not initialized any other way.
Since you do not do this, the compiler instead uses the default constructor for the nodes. You then create other nodes inside the constructor body, and assign them to the nodes in your class.
m_srcNode = Node(src);
m_dstNode = Node(dst);
Here, the two objects are first constructed with default constructor, then the overloaded constructed is called with Node(src) and Node(dst). After that, the implicitly defined copy assigner is called to assign the temporary objects to m_srcNode and m_dstNode. Finally the temporary objects are destroyed.
If you want to avoid extra constructor calls, you can write a member initializer list:
Edge::Edge(string src, string dst) : m_srcNode(src), m_dstNode(dst) {}
Take a look at this code:
#include <iostream>
using namespace std;
class A {
private:
int _x;
int _id;
static int count;
public:
A(int x) : _x(x) {
this->_id = A::count++;
cout << "Object with id " << this->_id
<< " has been created." << endl;
}
~A() {
cout << "Object with id " << this->_id
<< " has been destroyed." << endl;
}
int get_x(void) {
return this->_x;
}
A add(A& object) {
A tmp(this->_x + object._x);
return tmp;
}
};
int A::count = 1;
int main(void) {
A object_1(13);
A object_2(5);
A object_3(12);
object_3 = object_1.add(object_2);
cout << object_3.get_x() << endl;
return 0;
}
Here's the output from the program:
Object with id 1 has been created.
Object with id 2 has been created.
Object with id 3 has been created.
Object with id 4 has been created.
Object with id 4 has been destroyed.
18
Object with id 4 has been destroyed.
Object with id 2 has been destroyed.
Object with id 1 has been destroyed.
I don't understand what happened to Object with id 3? It definitely was created, but I see no line telling me that it was ever destroyed. Can you please tell me what's going on here?
As an aside question, why is it that when I use return 0, the destructors work fine, but when I use exit(EXIT_SUCCESS) I don't see Object with # has been destroyed printed on the screen as though the destructors are never called.
Is the previous object destroyed when the variable holding it gets assigned a new one using a copy constructor?
This question is moot because it is not possible to do so.
When you run
object_a = object_b;
this calls the assignment operator (not the copy constructor). It does not create or destroy any objects (unless your assignment operator does that).
In this case you haven't defined an assignment operator, so the default one is used, which overwrites object_3's ID with the other object's ID (which is 4). So when object_3 is destroyed it prints "Object with id 4 has been destroyed".
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to understand the following code:
blueberry bitCopy(blueberry a) {
cout << "bitCopy " << blueberry::blQuantity << endl;
return a;
}
void howMany() {
cout << blueberry::blQuantity << endl;
}
int main() {
blueberry firstBl;
howMany();
bitCopy(firstBl);
howMany();
}
class blueberry:
#ifndef header_h
#define header_h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class blueberry {
private:
static int blQuantity;
public:
blueberry();
~blueberry() {
blQuantity--;
}
friend blueberry bitCopy(blueberry a);
friend void howMany();
};
#endif
int blueberry::blQuantity = 0;
blueberry::blueberry() {
blQuantity++;
};
class blueberry is just some class that has a static int value blQuantity that increments in the constructor each time an object is created, and decrements in the destructor each time an object goes out of scope.
The read out from this program is:
1
bitCopy 1
-1
I was expecting 0 at the end rather than -1. Can someone explain this please?
PLEASE do not tell me I require a copy constructor. I am not trying to fix this code so that the object count works. I am instead trying to understand how this works and why the blQuantity is not the value I expect.
class blueberry is just some class that has a static int value blQuantity that increments in the constructor each time an object is created, and decrements in the destructor each time an object goes out of scope.
Are you sure that's each and every time one is created? I think there is something you've missed.
blueberry bitCopy(blueberry a)
That's pass-by-value; i.e., blueberry a here is a copy of what was submitted to bitCopy(). That invokes blueberry's copy constructor, which you have not defined. The compiler thus creates a simple one for you, which copies over any member values from the original object -- but it does NOT increment anything. If you want that, you'll have to define:
blueberry::blueberry (const blueberry&) // copy constructor
blueberry& operator= (const blueberry&) // copy assignment operator
You may also want a move constructor and move assignment operator -- see that wikipedia article about the "rule of three (or five)"
I linked in the above paragraph.
The reason blQuantity is -1 at the end is because there are actually two copies made with bitCopy(), one for the parameter and one for the return value. If you change it to:
blueberry bitCopy (blueberry &a)
I.e., using pass-by-reference, there will only be one copy and blQuantity will be 0 afterward. If you then make the return value void, there will be no copies made and blQuantity should be 1.
Here's a demonstration of the roles of the copy constructor and operator= (copy assignment operator):
#include <iostream>
#include <string>
using namespace std;
class A {
public:
string x;
A (string s) : x(s) {
cout << "A con " << "(" << x << ")\n";
}
A (const A& other) : x(other.x) {
x.append("-copy");
cout << "A copy " << "(" << x << ")\n";
}
A& operator= (const A& other) {
x = other.x;
x.append("[=]");
cout << "A assign " << "(" << x << ")\n";
return *this;
}
~A () { cerr << x << " A bye!\n"; }
};
A test (A a) {
return a;
}
int main (void) {
A a("#1");
cout << "test()\n";
A b = test(a);
cout << "Copy assign:\n";
b = a;
cout << "Exiting...\n";
return 0;
}
I'll step through the output from this:
A con (#1)
test()
A copy (#1-copy)
A copy (#1-copy-copy)
#1-copy A bye!
The first line is from A a("#1"). The last three lines are a result of A b = test(a). The first one is copying in the parameter, A test (test a). The second is the creation of the return value, which is a copy of the parameter, so the tag on the object is now #1-copy-copy. That initializes b in main(). When test() exits, the parameter object is destroyed, #1-copy A bye!.
Copy assign:
A assign (#1[=])
This is from b = a in main(). Notice that the previous version of b is not destroyed. This is because copy assignment is meant to turn one object into a copy of another; neither object is destroyed, but the contents of the target object is presumably changed, hence b's tag is now #1[=]. So predictably:
Exiting...
#1[=] A bye!
#1 A bye!
When the program ends, a and b are destroyed.
If you change the signature of test() to:
A& test (A &a)
You'll get this output:
A con (#1)
test()
A copy (#1-copy)
Copy assign:
A assign (#1[=])
Exiting...
#1[=] A bye!
#1 A bye!
Only two objects are ever created, a via the constructor and b via the copy con; both of them are not destroyed until the end. If you then do not use the return value of test(), only one object is ever created.
I ran the following code
#include <iostream>
using namespace std;
class Count
{
private:
int count;
public:
//Constructor
Count():count(0) { cout << "Constructor called" << endl; }
//Destructor
~Count() { cout << "Destructor called" << endl; }
//Display the value.
Count display()
{
cout << "The value of count is " << count << endl;
return *this;
}
};
int main()
{
Count C;
C.display();
}
Result :-
Constructor called
The value of count is 0
Destructor called
Destructor called
In the above case, the destructor is called twice, one for destruction of the "this" object and one for return from main.
Is my observation correct ??
Can anyone explain me also the temporary object created in this process like why it is created, if created??
You are returning a copy from display() method thus it needs to be destructed too. So, in your main you actually have 2 objects, one - implicitly.
The destructor is called twice because your display function returns a copy of the Count instance that it is called on. So that gets destroyed along with your C instance within main.
2 instances = 2 destructor calls.
If you specify and implement your function to return an instance of Count then it will do so. If you don't want this behaviour, then change the return type to void and don't return anything - then your code will contain just the one instance C.
Your code here
Count display() {
// ^^^^^
cout << "The value of count is " << count << endl;
return *this; // <<<<<<
}
creates an implicit copy of your instance that is returned and immediately destroyed, hence the second destructor call.
Yes correct.
Your function display() created a copy which made a second object.
if you return a reference you wouldn't get the copy.
Count& display() { return *this; }