Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is the destructor call after the std::move necessary?

In The C++ programming language Edition 4 there is an example of a vector implementation, see relevant code at the end of the message.

uninitialized_move() initializes new T objects into the new memory area by moving them from the old memory area. Then it calls the destructor on the original T object, the moved-from object. Why is the destructor call necessary in this case?

Here is my incomplete understanding: moving an object means that the ownership of the resources owned by the moved-from object are transferred to the moved-to object. The remainings in the moved-from object are some possible members of built-in types that do not need to be destroyed, they will be deallocated when the the vector_base b goes out of scope (inside reserve(), after the swap() call). All pointers in the moved-from object are to be put to nullptr or some mechanism is employed to drop ownership of moved-from object on those resources so that we are safe, then why call the destructor on a depleted object when the "vector_base b" destructor will anyway deallocate the memory after the swap is done?

I understand the need to explicitly call the destructor in the cases when it must be called because we have something to destruct (e.g. drop elements) but I fail to see its meaning after the std::move + deallocation of vector_base. I read some texts on the net and I'm seeing the destructor call of the moved-from object as an signal (to whom or what?) that the lifetime of the object is over.

Please clarify to me what meaningful work remains to be done by the destructor? Thank you!

The code snippet below is from here http://www.stroustrup.com/4th_printing3.html

template<typename T, typename A> void vector<T,A>::reserve(size_type newalloc) {     if (newalloc<=capacity()) return;                   // never decrease allocation     vector_base<T,A> b {vb.alloc,size(),newalloc-size()};   // get new space     uninitialized_move(vb.elem,vb.elem+size(),b.elem);  // move elements     swap(vb,b);                                 // install new base  } // implicitly release old space  template<typename In, typename Out> Out uninitialized_move(In b, In e, Out oo) {     using T = Value_type<Out>;      // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_)     for (; b!=e; ++b,++oo) {         new(static_cast<void*>(&*oo)) T{move(*b)};  // move construct         b->~T();                                // destroy     }     return oo;        } 
like image 300
cvomake Avatar asked Dec 14 '13 22:12

cvomake


People also ask

Why is std :: move necessary?

std::move itself does "nothing" - it has zero side effects. It just signals to the compiler that the programmer doesn't care what happens to that object any more. i.e. it gives permission to other parts of the software to move from the object, but it doesn't require that it be moved.

Why the destructor is called in reverse order in C++?

The destructors are called in exactly the reverse order of the constructors – this is important because of potential dependencies (in the derived-class constructor or destructor, you must be able to assume that the base-class subobject is still available for use, and has already been constructed – or not destroyed yet) ...

What happens when destructor is not called?

The object would be destroyed automatically and the destructor would be called as the object went out of scope when foo returns.

Do destructors need to be called?

No. You never need to explicitly call a destructor (except with placement new ). A class's destructor (whether or not you explicitly define one) automagically invokes the destructors for member objects. They are destroyed in the reverse order they appear within the declaration for the class.


1 Answers

Moving from an object just means that the moved-from object might donate its guts to live on in another live object shortly before it is [probably] going to die. Note, however, that just because an object donated its guts that the object isn't dead! In fact, it may be revived by another donating object and live on that object's guts.

Also, it is important to understand that move construction or move assignment can actually be copies! In fact, they will be copies if the type being moved happens to be a pre-C++11 type with a copy constructor or a copy assignment. Even if a class has a move constructor or a move assignment it may choose that it can't move its guts to the new object, e.g., because the allocators mismatch.

In any case, a moved from object may still have resources or need to record statistics or whatever. To get rid of the object it needs to be destroyed. Depending on the class's contracts it may even have a defined state after being moved from and could be put to new use without any further ado.

like image 64
Dietmar Kühl Avatar answered Oct 04 '22 05:10

Dietmar Kühl