I was running this code to figure out which whether an object is destructed after or before it is reassigned to. But I didn't get the expected output. The variable id is printed correctly by the included print function, but it fails with some other number when printed by the destructor, and the two are the same for both objects. Why does this happen?
#include <iostream>
#include <string>
class A {
static int _idx;
int id;
public:
A()
{
std::cout << "Default constructor" << std::endl;
id = _idx;
_idx++;
}
A(std::string&& str)
{
id = _idx;
_idx++;
std::cout << str << std::endl;
}
void print()
{
std::cout << id << std::endl;
}
~A()
{
std::cout << id << std::endl;
}
};
int A::_idx = 0;
int main(void)
{
A a;
a.print();
a = std::string("World");
}
Output:
Default constructor
0
World
1
1
EDIT: Removed sloppy code and added example output for clarification
Don't call the destructor explicitly. Simply allow the variable to go out of scope.
When A does go out of scope, the first thing to run is the destructor body, followed by any destructors for member variables in the class in the reverse order in which they are constructed, then the process continues for any base classes.
(Member variables are constructed in the order that they appear in the class declaration.)
In your code, the destructor is called twice since you constructing 2 instances of A; note that the compiler generated assignment operator is effectively the thing that causes the value of id to be 1 at the point of their destruction.
The title question:
Do member variables die off before the destructor is called?
The answer is No. All member variables are alive in the body of the destructor.
Question in the post:
The variable id is printed correctly by the included print function, but it fails with some other number when printed by the destructor, and the two are the same for both objects. Why does this happen?
That problem can be traced to the line:
a = std::string("World");
This calls the overloaded constructor of the class to create a temporary object and the temporary object is assigned to a. The problem here is the implementation of the constructor.
It used to be
A(std::string&& str)
{
std::cout << str << std::endl;
}
The constructor left the member variable uninitialized. Hence, the value of member variable could be anything.
Now that you changed it to
A(std::string&& str)
{
id = _idx;
_idx++;
std::cout << str << std::endl;
}
your program will work in a predictable manner.
Why are your last lines of output the way they are?
Consider the line
a = std::string("World");
It is equivalent to:
Constructor a temporary object. (its id is 1)
Assign the temporary object to a. Now a.id is 1.
Destroy the temporary object. The destructor gets called on the temporary. You get the output 1
When the function returns, a is destructed. The destructor gets call on a. Since a.id is set to 1, you get the output 1.
The destructor is called when the object needs to die. After the destructor runs, member variables are destructed in reverse order of declaration. Destructor runs first.
the two are the same for both objects. Why does this happen?
Because of this line.
a = std::string("World");
This constructs a second A, with id = 1 and assigns it to the first A making that id also 1.
That = is an assignment operator. It means "make the left thing like the right thing".
Related
I have some class A, which I can either construct using nothing, or an std::function. On destruction that given function should be called (in case there is one). My problem is that the object gets destroyed right after it is created and returned by my getSomeA() function which calls the std::function before it is supposed to be called. The function passed to the constructor should only be called once. Some example code:
#include <iostream>
#include <functional>
static void testFunction(const std::string& msg)
{
std::cout << "TestFunction: " << msg << "\n";
}
class A {
public:
A(void) = default;
A(const std::function<void()>& onDestroy) :
onDestroy(onDestroy)
{ }
~A(void)
{
if (onDestroy) onDestroy();
else std::cout << "in dtor but no onDestroy was set\n";
}
private:
std::function<void()> onDestroy;
};
A getSomeA(void)
{
return A(std::bind(testFunction, "the A that was created inside getSomeA"));
}
int main(void)
{
A b1;
std::cout << "After creating b1\n";
b1 = getSomeA();
std::cout << "After reassigning b1\n";
std::cout << "Here the program works with b1...\n";
}
The program outputs
After creating b1
TestFunction: the A that was created inside getSomeA
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
So the function is called before it is supposed to be called (at the end of int main()).
After adding a move constructor and assignment operator everything works as expected:
A(A&& other) :
onDestroy(std::exchange(other.onDestroy, nullptr))
{ }
A& operator=(A&& other)
{
onDestroy = std::exchange(other.onDestroy, nullptr);
return *this;
}
And the program outputs
After creating b1
in dtor but no onDestroy was set
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
The actual question: Where is the object destroyed for the first time so that testFunction is called? In getSomeA() or in the main function before the assignment but after the object was created in getSomeA()?
All the edits: I tried to bring down my question for one hour but since I have no idea about move/copy semantics in C++ that was pretty hard for me.
In the first version the object gets destroyed for the first time as part of returning the object constructed in getSomeA. Its return statement effectively constructs a temporary object, which then gets assigned to main's b1. If you ignore the process of returning from a function, the sequence of events is:
A <temporary object>(std::bind( ... )
b1=<temporary object>
<temporary object gets destroyed>
At this point the bound function gets called, as a result of the temporary object gets destroyed. The temporary object is a fully tricked out object, with all the rights and privileged granted thereof. Including a destructor.
But wait, there's more! b1 is a perfect bit-by-bit copy of the original object, with the bound function, before it got destroyed. So when b1 gets destroyed, the function gets called again.
This is the indirect consequence of the Rule Of Three. When an object owns a resource, and must maintain an exclusive ownership of the resource you will need to provide a copy and/or move constructor and and assignment operator to spell out exactly what should happen in that situation.
P.S. these rules change slightly with C++17's guaranteed copy elision, but the underlying concept is still the same.
I am trying to understand what does the C++ standard say about how/when the destructor should be called when an object is returned from the function -
Consider this simple struct and two functions -
#include <iostream>
int g = 0;
struct foo {
int myid;
foo() {
myid = g;
g++;
std::cout << "Created " << myid << std::endl;
}
~foo() {
std::cout << "Destroyed " << myid << std::endl;
}
};
foo bar(void) {
int i = 0;
for (foo s; i < 10; i++) {
if (i == 5)
return s;
}
}
foo bar2(void) {
int i = 0;
foo s;
for (; i < 10; i++) {
if (i == 5)
return s;
}
}
int main() {
bar();
bar2();
return 0;
}
I am trying to track how many times the destructor is called. The output from the above program is -
Created 0
Destroyed 0
Destroyed 0
Created 1
Destroyed 1
I can understand the behavior of bar2. An object is created once and destroyed (I believe the destructor is called from main). But in bar when the object is declared inside the loop. It cases the destructor to be called twice. What is the reason for this discrepancy?
Is it the case that the standard leaves this behavior to the implementation (because of copy elision?) and g++ just choses this behavior for the two cases? If so how can I write this function so that I get predictable behavior. I need the destructor to be called the exact same number of times as the constructor (and preferably in the reverse order). I am okay with the destructor being called twice as long as the constructor is being called twice too. The reason is because I am allocating some data inside the constructor and freeing it inside the destructor.
Add this code
foo(const foo& rhs) {
myid = g;
g++;
std::cout << "Created from copy " << myid << std::endl;
}
This is a copy constructor, it's being called as well only you weren't aware of it, because you were using the default version, which obviously doesn't print anything, or increment your counter.
cppinsights tells you what's happening: There's a default copy constructor being called, so a copy is being destructed as well.
There, however, both objects are subject to named return value optimisation, a variant of copy elision that elides the copy constructor. If you compile and run your code with clang, that is indeed the case (https://godbolt.org/z/KWhRpL doesn't have the double "Destroyed").
NRVO is optional, and it seems like gcc doesn't apply it there. There is no way to force NRVO to happen, but you could implement a move constructor which will be called instead.
This question already has answers here:
explicit call to destructor is not destroying my object why?
(7 answers)
Closed 4 years ago.
I want to explicitly call the destructor of an object in C++ to destroy that object.
This is just a simple program to experiment with the features of the programming languages. I have a default constructor which sets the internal data member to 1, and overloaded constructor which sets the internal data member to the parameter, and a destructor which displays the internal data member of the just destroyed object. There is also a function which prints the internal data member.
#include <iostream>
using std::cout;
using std::endl;
class myClass {
public:
myClass()
{
i = 1;
cout << "default ";
cout << "constructor called with " << this->i << endl;
}
myClass(int i)
{
this->i = i;
cout << "constructor called with " << this->i << endl;
}
~myClass()
{
cout << "object " << i << " destroyed!" << endl;
}
void printData()
{
cout << "object's data is " << i << endl;
}
private:
int i; // private data member
};
int main() {
myClass a;
myClass b;
myClass c(8);
a.printData();
b.printData();
c.printData();
/* I want to explicitly destroy object b. */
b.~myClass();
b.printData();
/* all the destructors get called when the objects go out of scope */
return 0;
}
My reasoning is this: I think that the destructor causes the object to be destroyed, so it no longer exists in the memory. After I explicitly call the destructor, I should be no longer able to use that object again, since it is destroyed. However, I am able to call a function of the object and print the value of the internal data member. Did manually calling the destructor fail to destroy the object? What's going on here?
Output:
default constructor called with 1
default constructor called with 1
constructor called with 8
object's data is 1
object's data is 1
object's data is 8
object 1 destroyed!
object's data is 1
object 8 destroyed!
object 1 destroyed!
object 1 destroyed!
Does calling the destructor destroy the object, or is calling the destructor a RESULT OF destroying the object?
After I explicitly call the destructor, I should be no longer able to use that object again, since it is destroyed
That's right. Only that it's C++ and instead of "you are no longer able" as in "you'll be warned when you do bad things", it's more like "you may be shot in the foot at any random point in the future without warning if you do bad things" (aka "undefined behavior").
In your particular example, you destroy the object, and it ceases to logically exist. The memory may still be allocated or even contain some old data. However, trying to access it is undefined behavior. It may "kind of work" on your specific combination of compiler, compiler flags, source code, OS and moon phase, it may work differently later, it technically may even wipe your hard drive.
Also, as you've declared the object in a local variable, it gets automatically destroyed second time when it goes out of the scope. That's also undefined behavior, but it does not really matter is your program's behavior is already completely undefined.
You may try catching such things with dynamical analysis like Valgrind, AddressSanitizer or UndefinedBehaviorSanitizer, but they provide no guarantees.
I am currently reading the second edition of C++: A Beginner's Guide by Herbert Schildt.
In Module 9.4, he talks about returning objects:
Just as objects can be passed to functions, functions can return objects. To return an object, first declare
the function as returning a class type. Second, return an object of that type using the normal return
statement. The following program has a member function called mkBigger( ). It returns an object that
gives val a value twice as large as the invoking object.
This is the 'following program' he mentions:
// Returning objects.
#include <iostream>
using namespace std;
class MyClass {
int val;
public:
// Normal Constructor.
MyClass(int i) {
val = i;
cout << "Inside constructor\n";
}
~MyClass() {
cout << "Destructing\n";
}
int getval() { return val; }
// Return an object.
MyClass mkBigger() {
Myclass o(val * 2); // mkBigger() returns a MyClass object.
return o;
}
};
void display(MyClass ob)
{
cout << ob.getval() << '\n';
}
int main()
{
cout << " Before Constructing a.\n";
MyClass a;
cout << "After constructing a.\n\n";
cout << "Before call to display.\n";
display(a);
cout << "After display() returns.\n\n";
cout << "Before call to mkBigger().\n";
a = a.mkBigger();
cout << "After mkBigger() returns.\n\n";
cout << "Before second call to display.\n";
display(a);
cout << "After display() returns.\n\n";
return 0;
}
This gives us the following output:
Before Constructing a.
Inside constructor
After constructing a.
Before call to display.
10
Destructing
After display() returns.
Before call to mkBigger()
Inside constructor
Destructing
Destructing
After mkBigger() returns.
Before second call to display.
20
Destructing
After display() returns.
Destructing
Schildt then goes on to explain that the reason there are two 'Destructing' messages during the mkBigger() call is because of the fact that:
when an object is returned by a function, a temporary object is automatically created, which holds the return value. It is this object that is actually returned by the function. After the value has been returned, this object is destroyed.
I was actually surprised there wasn't 3 'Destructing' messages. I have the following issue: Given the definition of mkBigger(), a new MyClass instance is created, and it is that instance that is returned and placed in the address of a. Thus, when doing
a = a.mkBigger();
My impression is thus that the original object previously held in a is no longer referenced by a. Is this correct? If so, I then have the following issues:
I was told C++ has some minute notions of garbage collection. Would that object thus be garbage-collected? where is this object now? Is this an example of the possible feared memory leaks that many mention when talking about the 'dangers' of C++?
One of the destructor in mkbigger() is called on o, the MyClass instance passed in by value; it goes out of scope at the end of the function. The other is called on the temporary copy of o returned when it is destroyed. What else goes out of scope? Not a in main(); therefore you should not expect a third destructor to be called. C++ does not provide garbage collection outside of calling destructors when automatic objects go out of scope.
Unlike some other modern languages, a does not "hold a reference" to an object; a is the object, in that it is a certain number of bytes holding the raw data members. When you do a = a.mkBigger();, MyClass's default assignment operator is called, which simply copies the val inside the temporary object on the right hand side into the val inside a, overwriting the value that was already there. a = a.makeBigger() would be equivalent to a.val = a.makeBigger().val if val were public.
Memory leaks occur when you use new to allocate memory and then fail to use delete to deallocate that memory. For classes that do this internally, you must write at least your own copy constructor, assignment operator, and destructor.
My friend told me C++ allows us to call a member function even if the instance is destroyed from memory. So I write the code below to verify it, but why the value of a can be extracted even after the object was destroyed? I thought there would be a segment fault.
#include <iostream>
class Foo{
public:
Foo(int a = 0){
std::cout << "created" << std::endl;
this->a = a;
}
~Foo(){
std::cout << "destroyed" << std::endl;
}
Foo *f(){
std::cout << "a=" << a << std::endl;
return this;
}
private:
int a;
};
Foo *iwanttocallf(int i){
return ((Foo)i).f();
}
int main(){
for(int i = 0; i < 3; i++)
iwanttocallf(i)->f();
}
Output from my Macbook Air:
created
a=0
destroyed
a=0
created
a=1
destroyed
a=1
created
a=2
destroyed
a=2
Usually compilers are implementing the member function call as a call to a regular c function with the first argument a pointer to the object (gcc does it like that as far as I know). Now if your pointer is pointing to one destroyed object it doesn't mean that the memory where the a has been stored will be changed, it might be changed. So it is undefined behavior in general. In your case you got a value of a but maybe next time with a different compiler or different code you will crash. Try to use placement new operator then set a value of 'a' = 0 in destructor... and follow the memory where the object is stored.
"My friend told me C++ allows us to call a member function even if the member is destroyed from memory"?
I don't know what your friend is trying to say. But you call member function on some object of a class
unless it's a static member. So, if you delete that object from memory, how could you call any function of that class on that object. It's an undefined behavior.
This is covered in ยง12.7 [class.cdtor]:
[..] For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior.
As other people have told, this involves undefined behavior, and any result is possible. I'll try to explain why you encountered this particular result (stuff working normally).
Objects in C++ are represented by contents of memory. When an object is destroyed, its
destructor is executed, but the memory still contains the previous value. The output operation outputs the value taken from memory (which is now "free" - doesn't belong to any object) - if there is not much stuff going on between the destructor call and the output, the old value will remain.
However, if you change your code to add some calculations, the bug will be evident. For example, I added the following function that simulates some calculations:
int do_stuff()
{
int result = 0;
int x[3] = {0};
for (auto& n: x)
{
n = rand();
result ^= n;
}
return result;
}
I also added a call to this function:
Foo *f(){
std::cout << "foo1: a=" << a << std::endl;
do_stuff();
std::cout << "foo2: a=" << a << std::endl;
return this;
}
I got the output:
foo1: a=0
foo2: a=424238335
This clearly shows that it's not safe to expect anything consistent when dealing with deleted objects.
By the way, some debuggers overwrite the memory that deleted objects occupied with a special value like 0xcdcdcdcd - to make some sense out of this kind of unpredictable behavior. If you execute your code under such a debugger, you will see garbage printed, and will immediately know that your code is buggy.