0

当一个新的容器被定义在一个std::array

#include <iostream>
#include <array>
#include <initializer_list>

// My container
template<typename Type, unsigned int Size>
class MyContainer
{
    // Lifecycle
    public:
        MyContainer() : _data() {}
        MyContainer(const MyContainer<Type, Size>& rhs) : _data(rhs.data()) {}
        MyContainer(const std::array<Type, Size>& rhs) : _data(rhs) {}
        template<typename... Types> MyContainer(const Types&... numbers) : _data({{numbers...}}) {}
        ~MyContainer() {}

    // Assignment
    public:
        MyContainer<Type, Size>& operator=(const MyContainer<Type, Size>& rhs) {_data = rhs.data(); return *this}

    // Accessors
    public:
        Type& operator[](const unsigned int i) {return _data[i];}
        const Type& operator[](const unsigned int i) const {return _data[i];}
        std::array<Type, Size>& data() {return _data;}
        const std::array<Type, Size>& data() const {return _data;}

    // Operators
    public:
        MyContainer<Type, Size> operator+(const MyContainer<Type, Size>& rhs)
        {
            MyContainer<Type, Size> result;
            for (unsigned int i = 0; i < Size; ++i) {
                result[i] = _data[i] + rhs[i];
            }
            return result;
        }

    // Data members
    protected:
        std::array<Type, Size> _data;
};

// Main
int main(int argc, char* argv[])
{
    // Initialization
    MyContainer<double, 4> x = {0., 1., 2., 3.};
    MyContainer<double, 4> y = {4., 5., 6., 7.};
    MyContainer<double, 4> z;

    // Operation
    z = x+y; // Can move semantics help here ?

    // Result
    std::cout<<z[0]<<" "<<z[1]<<" "<<z[2]<<" "<<z[3]<<std::endl;
    return 0;
}

移动语义可以通过避免一些副本来加速 main() 中的操作吗?

如果答案是肯定的,如何在当前设计中实现它?

4

2 回答 2

2

不,a 的所有数据std::array<double, N>都包含在对象本身中。移动语义仅在对象拥有外部引用资源(通常通过指针)时才有帮助,并且该引用可以被复制和取消。

于 2013-01-05T01:43:17.897 回答
0

因为MyContainer<double>没有任何优势,当你“移动” adouble时它实际上做了一个复制,因为 adouble没有资源可以移动,它只有一个值可以复制。

但是你的类型是一个模板,所以大概你打算将它用于除double. 对于MyContainer<std::string>MyContainer<HeavyweightType>值得定义移动操作。那很简单:

    MyContainer(MyContainer&&) = default;
    MyContainer& operator=(MyContainer&&) = default;

请注意,在类模板的定义中,您可以只说不MyContainerMyContainer<Type, Size>模板参数列表的类模板的名称指的是当前实例化,即MyContainer与 具有相同类型MyContainer<Type, Size>

您也可以简化一些其他特殊成员函数:

    MyContainer(const MyContainer&) = default;
    ~MyContainer() = default;

    MyContainer& operator=(const MyContainer>&) = default;

现在您的类型是可移动和可复制的,具有正确的语义,并且代码比您的原始版本更简单!

您还可以为这些函数添加移动支持:

    MyContainer(const std::array<Type, Size>& rhs) : _data(rhs) {}
    template<typename... Types> MyContainer(const Types&... numbers) : _data({{numbers...}}) {}

通过添加一个带有 rvaluearray的构造函数,并使构造函数模板使用通用引用和完美转发:

    MyContainer(const std::array<Type, Size>& rhs) : _data(rhs) {}
    MyContainer(std::array<Type, Size>&& rhs) : _data(std::move(rhs)) {}
    template<typename... Types> MyContainer(Types&&... numbers)
      : _data{{ std::forward<Types>(numbers)...}} {}

现在你的类型可以用右值初始化。

于 2013-01-06T13:59:17.070 回答