I have been reading the book "The C++ programing language 4th edition" by Bjarne Stroustrup (The creator of c++) and have been learning about move constructors and move assignments.
In the book for the class vector (see 1 for header below) he shows how to implement the move constructor (see 2 below) and says the move assignment is implemented in a similar manner but doesn't show how. I have implemented the move assignment myself (see 3 below) and everything seems to be working fine, however, I am not sure I have implemented it correctly.
I am not getting any errors and have looked at many examples but I cannot confirm its correct for my specific class. Can someone experienced with c++ please look at my code and comment if it is correct?
EDIT: Also please see 4 for constructors and destructor.
Thank you for your time.
P.S: Any helpful hints or modifications are welcome
1) Class Header File:
#ifndef VECTOR_H
#define VECTOR_H
#include <cstdlib>
#include <iostream>
#include <stdexcept>
using namespace std;
template<typename T>
class Vector {
public:
// constructors
Vector(int s);
Vector(std::initializer_list<T>);
// destructor
~Vector();
// copy constructor and copy assignment
Vector(Vector&);
Vector<T>& operator=(Vector&);
// move constructor and move assignment
Vector(Vector&&);
Vector<T>& operator=(Vector&&);
// operators
T& operator[](int);
const T& operator[](int) const; // the second const means that this function cannot change the state of the class
// we define operator[] the second time for vectors containing constant members;
// accessors
int getSize();
private:
int size;
T* elements;
};
#endif /* VECTOR_H */
2) Move constructor (implemented in the same way as book):
// move constructor
template<typename T>
Vector<T>::Vector(Vector&& moveme) : size{moveme.size}, elements{moveme.elements}
{
moveme.elements = nullptr;
moveme.size = 0;
}
3) Move assignment (not sure if correct):
// move assignment
template<typename T>
Vector<T>& Vector<T>::operator=(Vector&& moveme)
{
delete[] elements; // delete old values
elements = moveme.elements;
size = moveme.size;
moveme.elements = nullptr;
moveme.size = 0;
return *this;
}
4) Constructors and destructor:
#include <array>
#include "Vector.h"
// constructors
template<typename T>
Vector<T>::Vector(int s) {
if(s<0) throw length_error{"Vector::Vector(int s)"};
// TODO: use Negative_size{} after learning how to write custom exceptions
this->size = s;
this->elements = new T[s];
}
template<typename T>
Vector<T>::Vector(std::initializer_list<T> list) : size(list.size()),
elements(new T[list.size()])
{
copy(list.begin(), list.end(), elements);
}
// destructor
template<typename T>
Vector<T>::~Vector()
{
delete[] this->elements;
}
Since this question was answered in the comments I thought I'd follow the advice from the meta: Question with no answers, but issue solved in the comments (or extended in chat) and write a short Community Wiki to close and answer the question.
I will also add useful additional info and tips from other users who joined the discussion in the comments.
Bo Presson answering and providing additional info on template placement:
The move assignment seems reasonable, except that putting templates in a cpp file makes them usable in that cpp file only. See Why can templates only be implemented in the header file?
Rakete1111 clarifying a misconception I had regarding move semantics:
std::move != move semantics. You have move semantics, where rvalues can be moved (using the move constructor) instead of copied. std::move is just a facility to enable move semantics (like using the move constructor) for types that are not rvalues.
kim366 bringing up return optimization question with Jive Dadson and I answering:
... Also, is there really no return-value-optimization, if you don't have overloaded move ctors/assignments ? -kim366
It seems so, in the example (see function below) he says that
z = x + y + z
will copy the return result twice "If a Vector is large, say, 10,000 doubles, that could be embarrassing." But "Given that definition, the compiler will choose the move constructor to implement the transfer of the return value..." He invented c++ so ill just take his word for it :).Vector operator+(const Vector& a, const Vector& b) { if (a.size()!=b.size()) throw Vector_size_mismatch{}; Vector res(a.size()); for (int i=0; i!=a.size(); ++i) res[i]=a[i]+b[i]; return res; }
- hammeramr(Example was from the book: "The C++ programing language 4th edition" by Bjarne Stroustrup)
See also What is the copy-and-swap idiom? -Jive Dadson
Hope people find this useful and thanks for those who participated.