3

我一直在阅读 Bjarne Stroustrup(c++ 的创建者)的《C++ 编程语言第 4 版》一书,并且一直在学习移动构造函数和移动赋值。

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

我没有收到任何错误,并且查看了很多示例,但我无法确认它对于我的特定课程是否正确。有C++经验的人可以看看我的代码并评论是否正确?

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

感谢您的时间。

PS:欢迎任何有用的提示或修改

1)类头文件:

#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)移动构造函数(实现方式与book相同):

// 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;
}
4

1 回答 1

2

由于在评论中回答了这个问题,我想我会遵循元数据的建议:没有答案的问题,但在评论中解决了问题(或在聊天中扩展)并写了一个简短的社区 Wiki 来关闭并回答问题。

我还将在评论中添加来自其他参与讨论的用户的有用的附加信息和提示。

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

移动分配似乎是合理的,除了将模板放在 cpp 文件中使它们只能在该 cpp 文件中使用。请参阅 为什么模板只能在头文件中实现?

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

std::move != 移动语义。您有移动语义,其中右值可以移动(使用移动构造函数)而不是复制。std::move 只是为非右值类型启用移动语义(如使用移动构造函数)的工具。

kim366与Jive Dadson一起提出回报优化问题,我回答:

...此外,如果您没有重载移动 ctors/assignments,是否真的没有返回值优化?-kim366

似乎是这样,在示例中(请参见下面的函数),他说z = x + y + z将复制返回结果两次“如果向量很大,比如 10,000 个双精度数,那可能会很尴尬。” 但是“鉴于该定义,编译器将选择移动构造函数来实现返回值的传输......”他发明了 c++,所以我只好信守诺言:)。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; }- 锤子

(示例来自书中:Bjarne Stroustrup 的“C++ 编程语言第 4 版”

另请参阅 什么是复制和交换习语? ——杰夫·达森

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

于 2017-10-01T09:08:03.653 回答