Home > Enterprise >  Implement a swap function to get a move constructor in own container class
Implement a swap function to get a move constructor in own container class

Time:10-05

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;
};
  • Related