简体   繁体   English

根据移动赋值运算符移动构造函数

[英]Move constructor in terms of move assignment operator

In the codebase on our project, I found something like this: 在我们项目的代码库中,我发现了这样的事情:

struct MeshData {
    MeshData() {}
    MeshData(MeshData&& obj) { *this = std::move(obj); }
    MeshData& operator=(MeshData&& obj) {
        if (this != &obj) {
            indexes = std::move(obj.indexes);
        }
        return *this;
    }
    std::vector<int> indexes;
};

Implementing move construction in terms of the move assignment seems like a clever idea to me that reduces code duplication, but after looking for information I didn't find any especific advice regarding this. 在移动分配方面实现移动构造对我来说似乎是一个聪明的想法,减少了代码重复,但在查找信息之后,我没有找到任何关于此的具体建议。

My question is: Is this an antipattern or are there any situations where this shouldn't be done? 我的问题是:这是反模式还是有任何不应该做的情况?

This cannot be done if your type has data members with no default constructors, and should not be done if they have default constructors which are expensive: 如果您的类型的数据成员没有默认构造函数,则无法执行此操作,如果它们具有昂贵的默认构造函数,则不应执行此操作:

struct NoDefaultCtor {
    NoDefaultCtor() = delete;
    NoDefaultCtor(int){}
};

struct Foo {
    Foo(Foo&& obj) { *this = std::move(obj); }
    Foo& operator=(Foo&& obj) {
        if (this != &obj) {
            thing = std::move(obj.thing);
        }
        return *this;
    }
    NoDefaultCtor thing;
};

gives this error: 给出了这个错误:

<source>: In constructor 'Foo::Foo(Foo&&)':
<source>:10:20: error: use of deleted function 'NoDefaultCtor::NoDefaultCtor()'
     Foo(Foo&& obj) { *this = std::move(obj); }
                    ^
<source>:5:5: note: declared here
     NoDefaultCtor() = delete;

This is because all data members must be constructed before the body of the constructor is entered. 这是因为必须在输入构造函数体之前构造所有数据成员。

However, the best advice is to follow the Rule of Zero and avoid writing those special members at all. 但是,最好的建议是遵循零规则,并避免编写这些特殊成员。

One of the pitfalls of this approach can manifest itself when move constructors and move operators of member variables may yield different results. 当移动构造函数和移动成员变量的运算符可能产生不同的结果时,这种方法的一个缺陷就会表现出来。 For example this would happen if indexes was a vector using custom allocator with std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value evaluating to true . 例如,如果indexes是使用自定义分配器的vector并且std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value evaluation to true则会发生这种情况。 In this case dedicated move constructor would move both allocator and data without throwing exceptions while calling move assignment would result in new storage being allocated and all the items move constructed leading to considerable overhead and preventing move constructor from being no throwing. 在这种情况下,专用移动构造函数将移动分配器和数据而不抛出异常,而调用移动分配将导致分配新存储并且所有项目移动构造导致相当大的开销并防止移动构造函数不被抛出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM