Reputation: 476
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
Upvotes: 2
Views: 1013
Reputation: 172934
std::move
just produces an rvalue (xvalue); it won't perform move operation, it won't modify the argument at all.
In particular,
std::move
produces an xvalue expression that identifies its argumentt
. It is exactly equivalent to astatic_cast
to 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;
}
Upvotes: 6
Reputation: 4258
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.
Upvotes: 2