在C ++ 11中编写Copy / Move / operator = trio的“正确”方法是什么?

时间:2012-02-22 21:31:19

标签: c++ c++11

此时,编写复制构造函数和赋值运算符对是明确定义的;快速搜索将引导您充分了解如何正确编码这些内容。

现在移动构造函数已进入混合状态,是否有一种新的“最佳”方式?

4 个答案:

答案 0 :(得分:12)

最好,它们只是= default;,因为成员类型应该是资源管理类型,可以隐藏您的移动详细信息,例如std::unique_ptr。只有那些“低级”类型的实现者才应该为处理它而烦恼。

请记住,如果您持有外部(对象)资源,则只需要使用移动语义。对于“扁平”类型来说,这是完全没用的。

答案 1 :(得分:5)

最好的方法是让编译器全部生成它们。它也是C ++ 03中最好的方法,如果你设法做到这一点,当你迁移到C ++ 11时,你的C ++ 03类会自动变为“移动”。

大多数资源管理问题都可以通过编写单资源管理类的非复制构造函数和析构函数来解决,然后只使用这些构建复合类,加上智能指针(例如std::unique_ptr)和容器类来解决建立更丰富的对象。

答案 2 :(得分:4)

使用clang / libc ++:

#include <chrono>
#include <iostream>
#include <vector>

#if SLOW_DOWN

class MyClass
{
    void Swap(MyClass &other)
    {
        std::swap(other.member, member);
    }

public:
    MyClass()
        : member()
    {
    }

    MyClass(const MyClass &other)
        : member(other.member)
    {
    }

    MyClass(MyClass &&other)
        : member(std::move(other.member))
    {
    }

    MyClass &operator=(MyClass other)
    {
        other.Swap(*this);
        return *this;
    }

private:
    int member;
};

#else

class MyClass
{
public:
    MyClass()
        : member()
    {
    }

private:
    int member;
};

#endif

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration<float, std::milli> ms;
    auto t0 = Clock::now();
    for (int k = 0; k < 100; ++k)
    {
        std::vector<MyClass> v;
        for (int i = 0; i < 1000000; ++i)
            v.push_back(MyClass());
    }
    auto t1 = Clock::now();
    std::cout << ms(t1-t0).count() << " ms\n";
}

$ clang++ -stdlib=libc++ -std=c++11 -O3 -DSLOW_DOWN test.cpp 
$ a.out
519.736 ms
$ a.out
517.036 ms
$ a.out
524.443 ms

$ clang++ -stdlib=libc++ -std=c++11 -O3  test.cpp 
$ a.out
463.968 ms
$ a.out
458.702 ms
$ a.out
464.441 ms

这次测试的速度差异约为12%。

说明:其中一个定义有一个简单的复制构造函数和复制赋值运算符。另一个没有。 “Trivial”在C ++ 11中具有实际意义。这意味着允许实现使用memcpy来复制您的类。或者甚至复制你班级的大型数组。所以如果可以的话,最好让你的特殊成员变得微不足道。这意味着让编译器定义它们。如果您愿意,仍然可以使用= default声明它们。

答案 3 :(得分:2)

这就是我想出来的,但我不知道那里是否有更优化的解决方案。

class MyClass
{
    void Swap(MyClass &other)
    {
        std::swap(other.member, member);
    }

public:
    MyClass()
        : member()
    {
    }

    MyClass(const MyClass &other)
        : member(other.member)
    {
    }

    MyClass(MyClass &&other)
        : member(std::move(other.member))
    {
    }

    MyClass &operator=(MyClass other)
    {
        other.Swap(*this);
        return *this;
    }

private:
    int member;
};