Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use Move Constructors/Assignments

I've searched but cannot find the answer to "When" to use them. I just keep hearing that it's good because it saves me that extra copy. I went around putting it in every class I had but some how that didn't seem to make sense for some classes :S I've read countless tutorials on LValues and RValues and std::move vs. std::copy vs. memcpy vs. memmove, etc. And even read up on throw() but I'm not sure on when to use that either.

My code looks like:

struct Point
{
    int X, Y;

    Point();
    Point(int x, int y);
    ~Point();

    //All my other operators here..
};

Then I have a class array of that like(RAII sorta thing):

class PA
{
    private:
        std::vector<Point> PointsList;

    public:
        PA();
        //Variadic Template constructor here..
        ~PA();
        //Operators here..
 };

Should I be using a move constructor and copy constructor? I had it in the Point Class but it felt weird so I removed it. Then I had it in the PA class but I thought that it won't do anything much so I removed it too. Then in my bitmaps class my compiler was complaining about having pointer members but no overload so I did:

//Copy Con:
BMPS::BMPS(const BMPS& Bmp) : Bytes(((Bmp.width * Bmp.height) != 0) ? new RGB[Bmp.width * Bmp.height] : nullptr), width(Bmp.width), height(Bmp.height), size(Bmp.size), DC(0), Image(0)
{
    std::copy(Bmp.Bytes, Bmp.Bytes + (width * height), Bytes);
    BMInfo = Bmp.BMInfo;
    bFHeader = Bmp.bFHeader;
}

//Move Con:
BMPS::BMPS(BMPS&& Bmp) : Bytes(nullptr), width(Bmp.width), height(Bmp.height), size(Bmp.size), DC(0), Image(0)
{
    Bmp.Swap(*this);
    Bmp.Bytes = nullptr;
}

//Assignment:
BMPS& BMPS::operator = (BMPS Bmp)
{
    Bmp.Swap(*this);
    return *this;
}

//Not sure if I need Copy Assignment?

//Move Assignment:
BMPS& BMPS::operator = (BMPS&& Bmp)
{
    this->Swap(Bmp);
    return *this;
}

//Swap function (Member vs. Non-member?)
void BMPS::Swap(BMPS& Bmp) //throw()
{
    //I was told I should put using std::swap instead here.. for some ADL thing.
    //But I always learned that using is bad in headers.
    std::swap(Bytes, Bmp.Bytes);
    std::swap(BMInfo, Bmp.BMInfo);
    std::swap(width, Bmp.width);
    std::swap(height, Bmp.height);
    std::swap(size, Bmp.size);
    std::swap(bFHeader, Bmp.bFHeader);
}

Is this correct? Did I do something bad or wrong? Do I need throw()? Should my assignment and move assignment operators actually be the same like that? Do I need a copy assignment? Ahh so many questions :c The last forum I asked on could not answer all so I was left confused. Finally should I use unique_ptr for Bytes? (Which is an array of bytes/pixels.)

like image 422
Brandon Avatar asked Jun 18 '12 04:06

Brandon


2 Answers

There are some excellent thought's on Scott Meyer's blog:

First, not all copy requests can be replaced by moves. Only copy requests for rvalues are eligible for the optimization. Second, not all types support move operations that are more efficient than copying operations. An example is a std::array. Third, even types that support efficient move operations may support them only some of the time. Case in point: std::string. It supports moves, but in cases where std::string is implemented using SSO (the small string optimization), small strings are just as expensive to move as to copy!

Perhaps, you can categorize your types accordingly and then decide which all need move semantics. Note, that there are restrictions on the compiler auto-generating move ctors/assignment operators, so you would be well advised to keep those in mind. This helps when you are explicitly specifying move members.

For classes where you do not specify move members explicitly, there are a few spots of bother. There is also the problem of explicitly/implicitly deleted move member which inhibit copying from rvalues. A highly valuable source of issues with implicit generation of move members can be found in Stroustrup's paper titled To Move or Not to Move.

Regarding exception handling with move semantics I'd suggest Dave Abraham's post Exceptionally Moving.

I'll try to come back to this answer with some examples when I get the time. Hopefully, for the time being the above mentioned links will help you get started.

like image 179
dirkgently Avatar answered Oct 12 '22 22:10

dirkgently


First and foremost: Use the "Rule of Zero" wherever you can. See "The rule of three/five/zero" and "C-20".

Therefore: Your "weird" feeling was correct: Point and PA do not need explicit copy/move operators. Otherwise, the answers of dirkgently and dirvine and their references are fine reads for a more in-depths understanding.

As for BMPS it is certainly a good idea to provide explicit move operators.

like image 32
mdr Avatar answered Oct 12 '22 20:10

mdr