Hello everyone, I am confused about how to define move constructor in derived class. I do not know if it is correct to realize it as below. Since after std::move(x), x should not be used to access its members before assignment again.
But I used it in the derived class. If not, I can't find other ways to do it.
Could someone explain to me the correct way to define it?
class Base
{
public:
Base() = default;
Base(const std::string &s): bookNo(s) {}
Base(const Base &) = default;
Base(Base &&b): bookNo(std::move(b.bookNo)) {}
~Base() = default;
private:
std::string bookNo;
};
class Derived : public Base
{
public:
// ...
Derived(Derived &&d): Base(std::move(d)), revenue(std::move(d.revenue)) {}
// ???? d should not be used after std::move(d) to access revenue here in my opinion
private:
string revenue;
};
As revenue is type double and doesn't use dynamic memory, there's no point using move with revenue. move semantics are only for objects that use dynamic memory where memory pointers are swapped/copied etc and not the referenced memory.
Tip: You can hit "edit post", highlight your code and then press the <> formatting button. This will not automatically indent your code. That part is up to you.
You can use the "preview" button at the bottom to see how it looks.
First, thanks for your advice, @agent max.
I am sorry to use std::move() on double type (which is a bad example), and I changed it into string type. @seeplus.
But it is not my point. My question is that after std::move(x) used, x can not access its members. Like in this code, Base(std::move(d)), the move operation is done first, even if the parameter Base accepts is Base type, but for d(Derived type), it is already moved. It should not access its members. Did I make any misunderstanding here about std::move() ?
The std::move does not modify object. It is just a hint for overload resolution to choose the move ctor/assingment over copy ctor/assignment.
See https://en.cppreference.com/w/cpp/utility/move
It is the move constructor that modifies the object. Lets look at it:
1 2 3
Base::Base( Base &&b )
: bookNo( std::move(b.bookNo) )
{}
The only thing in b that is modified is the b.bookNo.
Therefore,
Base::Base( Base &&b )
: bookNo( std::move(b.bookNo) )
{}
You mean b.bookNo here is modified is because it called string::string(string &&), which modified the value of b.bookNo, right ?
According to your explanation, even if we used std::move(x); we can still use x to access its members and the members should have the same information like below:
1 2 3 4 5 6
Derived d("0-2-9999", "1-1-1111");
Base b(std::move(d));
cout << d.revenue << endl;
// here can we still get the output "1-1-1111" ??? guess yes, but not sure.
// while for d.bookNo, generally it may be null string depending on string::string(string &&).
Did I understand correctly this time ? Thank you for checking again.