#why Destructor obj behaving like this?

81 messages ยท Page 1 of 1 (latest)

thick storm
#
#include <iostream>
using namespace std;
class obj{
    public:
        int data;
        obj(int d)
            : data(d)
        {
            std::cout << "Constructor made for obj" << endl;
        }
        ~obj(){
            std::cout << "Destructor made for obj. data = " << data << endl;
        }
};

int main()
{
    {
        obj o1(25);
        {
            o1 = obj(10);
        }
    }
    return 0;
}

output is

Constructor made for obj
Constructor made for obj
Destructor made for obj. data = 10
Destructor made for obj. data = 10

why not last line of output is Destructor made for obj. data = 25, how its destroying same object 2 times!

plush depotBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

thick storm
#

my assumption is

int main()
{
    {
        obj o1(25);
        {
            o1 = obj(10);
        } // deleted obj(10)
    }// should have deleted obj(25) !?!????
    return 0;
}
rough rune
#

first, the temporary obj(10) gets destroyed, after assignment finishes

#

then, when you do return 0, o1 gets destroyed

thick storm
#

are there not 2 objects created?

rough rune
thick storm
rough rune
thick storm
#
Constructor made for obj
test print line 28
Constructor made for obj
Destructor made for obj. data = 10
test print line 30
test print line 32
Destructor made for obj. data = 10
test print line 34

rough rune
#

see how the temporary gets nuked before line 30?

thick storm
#

whats __LINE__?

rough rune
#

a macro that expands to an int constant - the current line

#

and I printed that

thick storm
#

ok, let me understand

rough rune
# thick storm ok, let me understand
#include <iostream>
using namespace std;
class obj{
    public:
        int data;
        obj(int d)
            : data(d)
        {
            std::cout << "Constructor made for obj" << endl;
        }
        obj(const obj& other)
        {
          std::cout << "obj(const obj&) called, no changes made" << endl;
        }
        obj& operator=(const obj& other)
        {
          std::cout << "obj& operator=(const obj&) called, no changes made" << endl;
          return *this;
        }
        ~obj(){
            std::cout << "Destructor made for obj. data = " << data << endl;
        }
};
#

use this

#

to force the compiler to not make changes when running assignment

thick storm
rough rune
thick storm
#
#include <iostream>

using namespace std;
class obj{
    public:
        int data;
        obj(int d)
            : data(d)
        {
            std::cout << "Constructor made for obj" << endl;
        }
        obj(const obj& other)
        {
          std::cout << "obj(const obj&) called, no changes made" << endl;
        }
        obj& operator=(const obj& other)
        {
          std::cout << "obj& operator=(const obj&) called, no changes made" << endl;
          return *this;
        }
        ~obj(){
            std::cout << "Destructor made for obj. data = " << data << endl;
        }
};

int main()
{
    {
        obj o1(25);
        {
            std::cout<<"test print line " << __LINE__<<"\n";
            o1 = obj(10);
            std::cout<<"test print line " << __LINE__<<"\n";
        } // deleted obj(10)
        std::cout<<"test print line " << __LINE__<<"\n";
    }// should have deleted obj(25) !?!????
    std::cout<<"test print line " << __LINE__<<"\n";
    return 0;
}
#

i think i got it

rough rune
thick storm
#
[oumuamua@fedora cpp_labs]$ ./a.out 
Constructor made for obj
test print line 37
Constructor made for obj
obj& operator=(const obj&) called, no changes made
Destructor made for obj. data = 10
test print line 39
test print line 41
Destructor made for obj. data = 25
test print line 43
rough rune
thick storm
#

o1 = obj(10);
it made a new object, did operator= then deleted itself on same line?

rough rune
#

in reverse order of their creation

thick storm
#

๐Ÿ˜ฎ

rough rune
#

where as

#

local variables, which have a name obviously get destroyed only when they reach out of scope

#

in reverse order of their declaration

#

this is why o1 was destroyed before line 43

thick storm
#

so that means o1 = obj(10); is changed for forever, it does not matter in which scope it was changed

rough rune
#

yes, you edited o1 obviously

#

with assignment operator

thick storm
#

so operator= just changes the value, not assignt to a new object!

rough rune
#

it's called assignment operator

#

I left it empty

thick storm
#

earlier i was thinking o1 = obj(10); gave o1 a new memory address

rough rune
#

intentionally

rough rune
#

it will always remain alive at that address, until it goes out of scope

thick storm
#

exactly!

#

awesome.

thick storm
#

๐Ÿ˜

rough rune
thick storm
#

i know, i do keep snippts, for understanding

rough rune
#

k, whatever

thick storm
#

thanks! awesome explanation

rough rune
#

in C++11 there are 2 more special member functions

#

move constructor and move assignment operator

#

but here, they won't make a difference

thick storm
#

oh

#

there is too much happening

rough rune
#

they are designed for cases like, "man, why do I have to make deep copies with the normal assignment operator, when this is a temporary that will die quickly anyways, why can't we just, steal the data of the temporary to save up on deep copying?"

#

for cases like, your obj class has heap allocated fields like, std::vector, std::string, etc, and they already implement "legal stealing semantics" a.k.a. move semantics

#

because, moving a vector means, literally copy one pointer

#

but, deep copying a vector means, allcoating more memory, and manually copying all the elements one by one, with their copy constructor

thick storm
thick storm
#

when i pass unordered_map into a function, i think it makes a copy

#

but not for a vector

rough rune
# thick storm when i pass unordered_map into a function, i think it makes a copy
void runSomething(std::unordered_map<int,int> elems)
{

}  

int main()
{
  runSomething(std::unordered_map<int,int>({{1,1}, {2,3}})); // first, a temporary gets constructed with the constructor of unordered_map which takes an initializer list of pairs, and then the move constructor is used to pass the parameter elems to the function runSomething, this skips a deep copy obviously

}
crystal ivy
crystal ivy
#

OK, I didn't read enough of the conversation.

thick storm
rough rune
#

@thick storm

thick storm
#

i will defininately look into that

plush depotBOT
#

@thick storm Has your question been resolved? If so, run !solved :)

thick storm
#

yes one sec

#

!solved