In all standard containers like std::map
or std::vector
there is a move constructor and a move assignment to avoid copying. I want to build my own Wector
class with the same functionalities. My class declaration looks as follows:
class Wector{
public:
~Wector();
Wector();
Wector(std::size_t s);
Wector(std::size_t s, const double nr);
Wector(const std::initializer_list<double> il);
//copy constructor
Wector(const Wector & w);
//move constructor
Wector(Wector&& w);
std::size_t size() const;
double* begin(); // iterator begin
double* end(); // iterator end
const double* begin() const; // const iterator begin
const double* end() const; // const iterator
const double& operator[](std::size_t i)const;
double& operator[](std::size_t i);
Wector& operator=(const Wector& w);
//move assignment
Wector& operator=(Wector&& w);
private:
std::size_t wsize;
void swap(Wector& w);
double *element; // double *element = new double[s]
};
To implement the move-assignment and constructor I need a customer swap
.
//move constructor
Wector::Wector(Wector&& w)
: Wector()
{
swap(w);
}
//move assignment
Wector& Wector::operator=(Wector&& w){
swap(w);
return *this;
}
But I have no idea how to implement the swap
function without having direct access to the data element
and without copying with help of the iterators.
void Wector::swap(Wector& v){
std::swap(wsize, v.size());
double * temp = new double[v.size()];
std::copy(w.begin(), w.end(), temp);
std::swap(element, temp);
delete [] temp; //edited
}
Does anybody know how it is implemented in the case of std::vector
?
CodePudding user response:
You can just swap the pointers themselves (and, of course, the sizes). It doesn't matter which instance allocated the storage and which deletes it, it'll only belong to one instance at a time.
CodePudding user response:
The swap you want will be something like:
void Wector::swap(Wector& v){
std::swap(wsize, v.wsize);
std::swap(element, v.element);
}
CodePudding user response:
Your swap is not a move but a copy. You can just move each member:
//move assignment
Wector& Wector::operator=(Wector&& w){
// instead of "delete element" we use the correct Destructor for delete the old data.
// But for this the swap method should be optimized by exchange just the pointer and the size!
Vector().swap(this); // old vector is swapped in temporary object and then cleaned up in destuctor
// members of w are accessible becasuse operator= is a class member function.
// NOTE: surround with std::move is superfluous here, I do it for clarity of expression/intention.
// Unfortunately the C standard does not reset the values to default, so we do it afterwards.
this->wsize = std::move( w.wsize );
this->element = std::move( w.element );
// set values of the moved object to 0
// (we must avoid double deleting element!)
w.wsize = 0;
w.element = nullptr;
return *this;
};
Same you can do for the Move Constructor.
EDIT fixed cleanup the old data.
EDIT well, this brings me to the right solution:
//move assignment
Wector& Wector::operator=(Wector&& w){
// *** using 2 swaps for make the move! ***
// But for this the swap method should be optimized by exchange just the pointer and the size!
// first exchange the values
this->swap( w );
// if swap did not throw (in this example the optimized swap can be made noexcept)
// this now has the new values and w the old.
// Now delete the old values by using a new temporary which will use the destructor for cleanup.
Vector().swap(w);
// w is empty now and old data deleted.
return *this;
};