移动构造函数和移动赋值

Move Constructor & Move Assignment

我一直在阅读 Bjarne Stroustrup(C++ 的创造者)的书 "The C++ programing language 4th edition",并且一直在学习移动构造函数和移动赋值。

在有关 class 向量的书中(参见下面 header 的 1)他展示了如何实现移动构造函数(参见下面的 2)并说移动赋值是在类似的实现中方式,但没有说明如何。我自己实施了移动分配(参见下面的 3)并且一切似乎都运行良好,但是,我不确定我是否正确实施了它。

我没有收到任何错误并查看了很多示例,但我无法确认它是否适合我的特定 class。有 c++ 经验的人可以看看我的代码并评论它是否正确吗?

编辑:另请参阅 4 的构造函数和析构函数。

感谢您的宝贵时间。

P.S: 欢迎任何有用的提示或修改

1) Class Header 文件:

#ifndef VECTOR_H
#define VECTOR_H

#include <cstdlib>
#include <iostream>
#include <stdexcept>

using namespace std;

template<typename T>
class Vector {

public:
    // constructors
    Vector(int s);
    Vector(std::initializer_list<T>);

    // destructor
    ~Vector();

    // copy constructor and copy assignment
    Vector(Vector&);
    Vector<T>& operator=(Vector&);

    // move constructor and move assignment
    Vector(Vector&&);
    Vector<T>& operator=(Vector&&);

    // operators
    T& operator[](int);
    const T& operator[](int) const; // the second const means that this function cannot change the state of the class
                                    // we define operator[] the second time for vectors containing constant members;
    // accessors
    int getSize();


private:
    int size;
    T* elements;

};

#endif /* VECTOR_H */

2)移动构造函数(实现方式同书):

// move constructor 
template<typename T>
Vector<T>::Vector(Vector&& moveme) : size{moveme.size}, elements{moveme.elements}
{
    moveme.elements = nullptr;
    moveme.size = 0;
}

3)移动赋值(不确定是否正确):

// move assignment
template<typename T>
Vector<T>& Vector<T>::operator=(Vector&& moveme) 
{
    delete[] elements; // delete old values
    elements = moveme.elements;
    size = moveme.size;
    moveme.elements = nullptr;
    moveme.size = 0;
    return *this;
}

4)构造函数和析构函数:

#include <array>

#include "Vector.h"

// constructors
template<typename T>
Vector<T>::Vector(int s) {    
    if(s<0) throw length_error{"Vector::Vector(int s)"};
    // TODO: use Negative_size{} after learning how to write custom exceptions
    this->size = s;
    this->elements = new T[s];
}

template<typename T>
Vector<T>::Vector(std::initializer_list<T> list) : size(list.size()), 
        elements(new T[list.size()]) 
{
    copy(list.begin(), list.end(), elements);
}

// destructor
template<typename T>
Vector<T>::~Vector()
{
    delete[] this->elements;
}

既然这个问题在评论中得到了回答,我想我会听从 meta 的建议:Question with no answers, but issue solved in the comments (or extended in chat) 并写一个简短的社区 Wiki 来结束并回答这个问题。

我还会在评论中添加其他参与讨论的用户提供的有用信息和提示。

Bo Presson 回答并提供有关模板放置的附加信息:

The move assignment seems reasonable, except that putting templates in a cpp file makes them usable in that cpp file only. See Why can templates only be implemented in the header file?

Rakete1111 澄清我对移动语义的误解:

std::move != move semantics. You have move semantics, where rvalues can be moved (using the move constructor) instead of copied. std::move is just a facility to enable move semantics (like using the move constructor) for types that are not rvalues.

kim366 bringing up return optimization question with Jive Dadson 我回答:

... Also, is there really no return-value-optimization, if you don't have overloaded move ctors/assignments ? -kim366

It seems so, in the example (see function below) he says that z = x + y + z will copy the return result twice "If a Vector is large, say, 10,000 doubles, that could be embarrassing." But "Given that definition, the compiler will choose the move constructor to implement the transfer of the return value..." He invented c++ so ill just take his word for it :). Vector operator+(const Vector& a, const Vector& b) { if (a.size()!=b.size()) throw Vector_size_mismatch{}; Vector res(a.size()); for (int i=0; i!=a.size(); ++i) res[i]=a[i]+b[i]; return res; } - hammeramr

(Example was from the book: "The C++ programing language 4th edition" by Bjarne Stroustrup)

See also What is the copy-and-swap idiom? -Jive Dadson

希望人们觉得这有用,并感谢那些参与的人。