首页 > 解决方案 > 为什么我的数据元素被复制而不是移动?

问题描述

我正在执行一些关于移动语义的测试,我的课堂行为对我来说似乎很奇怪。

鉴于模拟类VecOfInt

class VecOfInt {
public:
    VecOfInt(size_t num) : m_size(num), m_data(new int[m_size]) {}
    ~VecOfInt() { delete[] m_data; }
    VecOfInt(VecOfInt const& other) : m_size(other.m_size),  m_data(new int[m_size]) {
        std::cout << "copy..." <<std::endl;
        std::copy(other.m_data, other.m_data + m_size, m_data);
    }
    VecOfInt(VecOfInt&& other) : m_size(other.m_size) {
        std::cout << "move..." << std::endl;
        m_data = other.m_data;
        other.m_data = nullptr;
    }
    VecOfInt& operator=(VecOfInt const& other) {
        std::cout << "copy assignment..." << std::endl;
        m_size = other.m_size;
        delete m_data;
        m_data = nullptr;
        m_data = new int[m_size];
        m_data = other.m_data;
        return *this;
    }
    VecOfInt& operator=(VecOfInt&& other) {
        std::cout << "move assignment..." << std::endl;
        m_size = other.m_size;
        m_data = other.m_data;
        other.m_data = nullptr;
        return *this;
    }
private:
    size_t m_size;
    int* m_data;
};
  1. 好的案例

    我就地插入单个值时:

    int main() {
        std::vector<VecOfInt> v;
        v.push_back(10);
        return 0;
    }
    

    然后它给了我以下输出(我认为很好)

    move...

  2. 奇怪的情况

    我就地插入三个不同的值时:

    int main() {
        std::vector<VecOfInt> v;
        v.push_back(10);
        v.push_back(20);
        v.push_back(30);
        return 0;
    }
    

    然后输出调用复制构造函数 3 次:

    move... move... copy... move... copy... copy...

我在这里缺少什么?

标签: c++c++11stdvectormove-semanticsmove-constructor

解决方案


重新分配时不使用移动构造和移动分配,std::vector除非它们是noexcept或没有复制替代方案。这是您noexcept添加的示例:

class VecOfInt {
public:
    VecOfInt(size_t num) : m_size(num), m_data(new int[m_size]) {}
    ~VecOfInt() { delete[] m_data; }
    VecOfInt(VecOfInt const& other) : m_size(other.m_size),  m_data(new int[m_size]) {
        std::cout << "copy..." <<std::endl;
        std::copy(other.m_data, other.m_data + m_size, m_data);
    }
    VecOfInt(VecOfInt&& other) noexcept : m_size(other.m_size) {
        std::cout << "move..." << std::endl;
        m_data = other.m_data;
        other.m_data = nullptr;
    }
    VecOfInt& operator=(VecOfInt const& other) {
        std::cout << "copy assignment..." << std::endl;
        m_size = other.m_size;
        delete m_data;
        m_data = nullptr;
        m_data = new int[m_size];
        m_data = other.m_data;
        return *this;
    }
    VecOfInt& operator=(VecOfInt&& other) noexcept {
        std::cout << "move assignment..." << std::endl;
        m_size = other.m_size;
        m_data = other.m_data;
        other.m_data = nullptr;
        return *this;
    }
private:
    size_t m_size;
    int* m_data;
};

一个活生生的例子输出:

move...
move...
move...
move...
move...
move...

这样做是为了保持异常安全。调整大小std::vector失败时,它将尝试使向量保持尝试前的状态。但是,如果移动操作在重新分配中途抛出,则没有安全的方法可以撤消已经成功进行的移动。他们也很可能会扔。如果移动可能会抛出,最安全的解决方案是复制。


推荐阅读