何时使用移动构造器/分配

Bra*_*don 6 c++ move-semantics c++11

我已经搜索但找不到"何时"使用它们的答案.我只是听说它很好,因为它为我节省了额外的副本.我把它放在我所拥有的每一堂课中,但有些课程似乎对某些课程没有意义:我读过无数关于LValues和RValues以及std :: move vs. std :: copy vs. memcpy的教程与memmove等等.甚至读取throw(),但我不知道何时使用它.

我的代码看起来像:

struct Point
{
    int X, Y;

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

    //All my other operators here..
};
Run Code Online (Sandbox Code Playgroud)

然后我有一个类数组(RAII sorta thing):

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

    public:
        PA();
        //Variadic Template constructor here..
        ~PA();
        //Operators here..
 };
Run Code Online (Sandbox Code Playgroud)

我应该使用移动构造函数和复制构造函数吗?我在Point Class中有它,但感觉很奇怪,所以我把它删除了.然后我在PA课上有它,但我认为它不会做任何事情所以我也删除了它.然后在我的bitmaps类中,我的编译器抱怨有指针成员但没有重载,所以我做了:

//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);
}
Run Code Online (Sandbox Code Playgroud)

它是否正确?我做错了什么或错了吗?我需要throw()吗?我的任务和移动任务操作员实际上应该是这样吗?我需要复印作业吗?啊,这么多问题:c我问过的最后一个论坛都无法回答所有问题,所以我感到很困惑.最后我应该使用unique_ptr作为字节吗?(这是一个字节/像素数组.)

dir*_*tly 12

Scott Meyer的博客上有一些很好的想法:

首先,并非所有复制请求都可以由移动替换.只有rvalues的复制请求才有资格进行优化.其次,并非所有类型都支持比复制操作更有效的移动操作.一个例子是std :: array.第三,即使支持高效移动操作的类型也可能仅在某些时候支持它们.例证:std :: string.它支持移动,但是在使用SSO(小字符串优化)实现std :: string的情况下,小字符串移动和复制一样昂贵!

也许,您可以相应地对类型进行分类,然后决定哪些都需要移动语义.请注意,编译器自动生成移动控制器/赋值运算符存在限制,因此建议您牢记这些.当您明确指定移动成员时,这会有所帮助.

对于没有明确指定移动成员的类,有一些麻烦.还存在显式/隐式删除的移动成员的问题,其禁止从rvalues复制.隐藏生成移动成员的一个非常有价值的问题来源可以在Stroustrup的题为"移动或不移动 "的论文中找到.

关于移动语义的异常处理,我建议Dave Abraham的帖子Exceptionally Moving.

当我有时间时,我会尝试用一些例子来回答这个答案.希望暂时上述链接可以帮助您入门.


mdr*_*mdr 5

首先也是最重要的:尽可能使用“零规则”。参见“三/五/零规则”和“ C-20 ”。

因此:您的“怪异”感觉是正确的:Point并且PA不需要明确的复制/移动操作符。否则,dirkgentlydirvine的答案以及他们的参考文献都是很好的读物,可以更深入地理解。

至于BMPS提供明确的移动操作符当然是一个好主意。