I try to understand the move constructor.
I allocate memory in the class' constructor and destroy it in the destructor.
When I try to move the class, I still have a double free.
#include <algorithm>
class TestClass
{
public:
TestClass() {a_ = new int[1];}
TestClass(TestClass const& other) = delete;
TestClass(TestClass && other) noexcept // = default;
{
this->a_ = std::move(other.a_);
}
~TestClass() {delete[] a_;}
private:
int* a_ = nullptr;
};
int main( int argc, char** argv )
{
TestClass t;
TestClass t2 = std::move(t);
}
Why std::move do not change to nullptr other.a_ ?
I have the same problem if the move constructor is default.
I found the following questions but I still don't know why the move operator don't change the source variable to default value.
How does std::move invalidates the value of original variable?
C++ how to move object to a nullptr
C++ std::move a pointer
std::move just produces an rvalue (xvalue); it won't perform move operation, it won't modify the argument at all.
In particular,
std::moveproduces an xvalue expression that identifies its argumentt. It is exactly equivalent to astatic_castto an rvalue reference type.
Given this->a_ = std::move(other.a_);, as built-in type, i.e. int*, this->a_ is just copy-assigned from ohter.a_, then both the pointers point to the same object. The defaulted move constructor does the same thing in fact. (It performs member-wise move operation on the data members; note that for built-in types the effect of move is same as copy.)
You need to set other.a_ to nullptr explicitly if you want to define that after moved the object should contain a null pointer.
E.g.
TestClass(TestClass && other) noexcept
{
this->a_ = other.a_;
other.a_ = nullptr;
}
First, std::move is just a cast which leads to other.a_ to be treated as an rvalue. For pointers, a move is just a copy.
This is so, I presume, because clearing the source pointer is not necessary in all cases and it would cause overhead in the cases where it's not needed.
You need to do the clearing explicitly.
Or, even simpler, just use std::unique_ptr<int> a_. Then you don't need to define any special member functions and the class behaves as you would imagine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With