Reputation: 4019
If I have a C++ class with copy and move constructors and copy assignment like so:
class Foo {
public:
int A[];
// custom ctor
Foo(size_t N) {
A = new A[N];
for(int i = 0; i < N; i++) A[i] = i * i;
}
// copy ctor
Foo(Foo& other) {
size_t N = sizeof(other.A) / sizeof(int);
A = new A[N];
for(int i = 0; i < N; i++) A[i] = other.A[i];
}
// move ctor
Foo(Foo&& other) {
A = other.A;
other.A = nullptr;
}
// copy assignment AND move assignment?
Foo& operator=(Foo other) {
std::swap(this.A, other.A);
return *this;
}
// default dtor
~Foo() {
delete[] A;
}
Can I in this case simply avoid defining a move assignment operator and assume that still move assignment is taking place when possible?
My reasoning behind that is: the copy assignment operator has to construct the Foo
object defined as parameter. Now it can choose between the copy ctor and the move ctor as both are available. Thus if given an rvalue
it should choose the move ctor and if given an lvalue
it should choose the copy ctor. Is this correct?
Also: will this implementation work regarding the sizeof
calculation of the array? If not, why not?
Upvotes: 2
Views: 141
Reputation: 6861
You can always don't define the move ctor and assignment operators. All you will lose is opportunity of performance gains. So no, no need for move assignment.
In your case, this example Foo f = Foo(); f = Foo()
you're using the normal assignment operator, where you could be doing a move
. You will do that in two moves instead plus the swap
.
About you EDIT: except for VLA, where it performs a run-time check, so it is correct.sizeof
question, it wont work. sizeof
will return the size of the pointer type, which is constant
Upvotes: 0
Reputation: 283971
Recommendation: Use std::vector
Problem: int A[];
is a flexible array member, which gets its storage from extra memory adjacent to the main object. You can't do A = new int[N];
nor sizeof (A)
.
Fix: You can use int* A;
and keep track of the size yourself, because sizeof
a pointer isn't related to the size of the array it points to.
Better: std::vector<int>
remembers its size and implements destructor, move, and copy operations so you don't have to.
Regarding the question about implementing assignment using pass-by-value: Yes, that's legal, it's even an idiom: "copy-and-swap". However, it will cause an unnecessary extra move in the move assignment case, so you may want to implement that directly. Or not, since two moves should barely cost more than the required one.
If you use std::vector
to store your data, the compiler-generated copy and move operations will do the right thing automatically.
Upvotes: 3