代码之家  ›  专栏  ›  技术社区  ›  asmmo

移动构造函数错误并使用移动构造函数进行委派[已关闭]

  •  0
  • asmmo  · 技术社区  · 7 年前

    为什么移动分配运算符的这个实现会在附加图像中给出错误

    image

    Spreadsheet::Spreadsheet(Spreadsheet&& src) noexcept :Spreadsheet(src.width, src.height) {
        this->cells = src.cells; // Shallow copy of data
        src.cells = nullptr; src.width = 0; src.height = 0; // Reset the source object, because ownership has been moved!
    
    };
    
    Spreadsheet& Spreadsheet::operator=(Spreadsheet&& rhs) noexcept {
        if (this == &rhs) return *this;
        for (size_t i = 0; i < width; i++) delete[] cells[i];
    
        delete[] cells;
        this->width = rhs.width; this->height = rhs.height;
        this->cells = rhs.cells;
        rhs.cells = nullptr; rhs.width = 0; rhs.height = 0;
        return *this;
    };
    

    我附上了全部资源。

    电子表格类定义 电子表格.h

    #pragma once
    #include "SpreadsheetCell.h"
    
    
    
    class Spreadsheet
    {
    public:
        Spreadsheet(size_t, size_t);
        ~Spreadsheet();//1
        void setCellAt(size_t, size_t, const SpreadsheetCell&);
        void verifyCoordinate(size_t, size_t) const;
        void swap(Spreadsheet);
        SpreadsheetCell& getCellAt(size_t, size_t);
        Spreadsheet(const Spreadsheet&);  //copy constructor 2
        Spreadsheet& operator=(const Spreadsheet& rhs);  //assignment operator 3
        Spreadsheet(Spreadsheet&& src) noexcept; // Move constructor 4
        Spreadsheet& operator=(Spreadsheet&& rhs) noexcept; // Move assign 5
    private:
        size_t width = 0;
        size_t height = 0;
        SpreadsheetCell** cells = nullptr;
    };
    

    电子表格类实现 电子表格.cpp

    #include "stdafx.h"
    #include "Spreadsheet.h"
    
    
    #include<utility>
    
    
    Spreadsheet::Spreadsheet(size_t width, size_t height) :width(width), height(height)
    {
        cells = new SpreadsheetCell*[width];
        for (size_t i = 0; i < height; i++) cells[i] = new SpreadsheetCell[height];
    }
    
    void Spreadsheet::verifyCoordinate(size_t x, size_t y) const
    {
        (x >= width || y >= height) ? throw std::out_of_range("") : void();// void();
    }
    
    
    
    void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
    {
        verifyCoordinate(x, y);
        cells[x][y] = cell;
    }
    
    SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) {
        verifyCoordinate(x, y);
        return cells[x][y];
    }
    
    Spreadsheet::~Spreadsheet()
    {
        for (size_t i = 0; i < width; i++) {
            delete[] cells[i];
        };
        delete[] cells;
        cells = nullptr;
    }
    
    Spreadsheet::Spreadsheet(const Spreadsheet& src) :Spreadsheet(src.width, src.height) {
        for (size_t i = 0; i < width; i++)
            for (size_t j = 0; j < height; j++) cells[i][j] = src.cells[i][j];
    }
    void Spreadsheet::swap(Spreadsheet copyOfRhsDueToBassByVal) {
        std::swap(copyOfRhsDueToBassByVal.width, this->width);
        std::swap(copyOfRhsDueToBassByVal.height, this->height);
        std::swap(copyOfRhsDueToBassByVal.cells, this->cells);
    }
    Spreadsheet& Spreadsheet::operator=(const Spreadsheet &rhs) {
        if (this == &rhs) return *this;//we cant use return rhs because it is const but the function header returnning a non-const;
        swap(rhs); return *this;
    }
    
       Spreadsheet::Spreadsheet(Spreadsheet&& src) noexcept :Spreadsheet(src.width, src.height) {
        this->cells = src.cells; // Shallow copy of data
        src.cells = nullptr; src.width = 0; src.height = 0; // Reset the source object, because ownership has been moved!
    
    };
    
    Spreadsheet& Spreadsheet::operator=(Spreadsheet&& rhs) noexcept {
        if (this == &rhs) return *this;
        for (size_t i = 0; i < width; i++) delete[] cells[i];
    
        delete[] cells;
        this->width = rhs.width; this->height = rhs.height;
        this->cells = rhs.cells;
        rhs.cells = nullptr; rhs.width = 0; rhs.height = 0;
        return *this;
    };
    

    电子表格单元格类定义 电子表格单元格.h

    #pragma once
    #include <string>
    #include <string_view>
    #include<iostream>
    
    using namespace std;
    
    class SpreadsheetCell
    {
    public:
        SpreadsheetCell() = default;
        SpreadsheetCell(double initialValue);
        SpreadsheetCell(std::string_view initialValue);
        void setValue(double);
        double getValue() const;
    
        void setString(std::string_view);
        string getString() const;
    
    private:
        string doubleToString(double) const;
        double stringToDouble(std::string_view) const;
    
        double value = 0;
    };
    

    spreadsheetcell类实现

    电子表格cell.cpp

    #include "stdafx.h"
    #include "SpreadSheetCell.h"
    
    
    
    SpreadsheetCell::SpreadsheetCell(double value) :value(value) {};
    SpreadsheetCell::SpreadsheetCell(std::string_view strv) { value = stringToDouble(strv); };
    
    void SpreadsheetCell::setValue(double value) { this->value = value; };
    double SpreadsheetCell::getValue() const { return value; };
    
    void SpreadsheetCell::setString(std::string_view str) { value = stringToDouble(str); };
    string SpreadsheetCell::getString() const { return doubleToString(value); };
    
    string SpreadsheetCell::doubleToString(double inValue) const {
        return to_string(inValue);
    }
    double SpreadsheetCell::stringToDouble(string_view strv) const {
        return strtod(strv.data(), nullptr);
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Remy Lebeau    7 年前

    代码中有几个逻辑错误:

    • 分配构造函数没有正确地循环通过第一个维度数组。您正在使用 width 元素的数目,然后在其中循环 height 取而代之的是元素的数量。如果 width < height ,则超出数组的界限并损坏内存。如果 width > height ,则不填充整个数组,只留下不确定值的指针。

    • 你的移动构造函数正在泄漏内存。它委托给分配构造函数而不是默认构造函数,因此分配了一个新数组,然后泄漏该数组。move构造函数根本不应该分配任何内容。

    • 你的 swap() 没有正确交换。目的 SWAP() 是交换两个对象的内容,但输入参数是按值传递的,因此传递给它的任何对象都会先被复制,然后再与复制的对象交换,而不是与原始对象交换。原始对象不变。所以必须通过引用传递参数。

    此外,move构造函数和move赋值运算符的一个典型且可取的实现是简单地交换moved to和moved from对象的内容。让moved from对象的析构函数释放任何旧资源。在移动新资源之前,不要浪费时间释放旧资源。

    改为尝试类似的操作:

    #pragma once
    #include "SpreadsheetCell.h"
    
    class Spreadsheet
    {
    public:
        Spreadsheet() = default;
        Spreadsheet(size_t, size_t);
        Spreadsheet(const Spreadsheet &);
        Spreadsheet(Spreadsheet &&) noexcept;
        ~Spreadsheet();
    
        Spreadsheet& operator=(const Spreadsheet &);
        Spreadsheet& operator=(Spreadsheet &&) noexcept;
    
        SpreadsheetCell& getCellAt(size_t, size_t);
        void setCellAt(size_t, size_t, const SpreadsheetCell&);
    
        void swap(Spreadsheet &);
    
    private:
        size_t width = 0;
        size_t height = 0;
        SpreadsheetCell** cells = nullptr;
    
        void verifyCoordinate(size_t, size_t) const;
    };
    
    void swap(Spreadsheet &lhs, Spreadsheet &rhs);
    

    #include "stdafx.h"
    #include "Spreadsheet.h"
    #include <utility> 
    
    Spreadsheet::Spreadsheet() noexcept
        : cells(nullptr), width(0), height(0)
    {
    }
    
    Spreadsheet::Spreadsheet(int width, int height)
        : cells(nullptr), width(width), height(height)
    {
        cells = new SpreadsheetCell*[width];
        for (size_t i = 0; i < width; ++i)
            cells[i] = new SpreadsheetCell[height];
    }
    
    Spreadsheet::Spreadsheet(const Spreadsheet &src)
        : Spreadsheet(src.width, src.height)
    {
        for (size_t i = 0; i < width; ++i)
            for (size_t j = 0; j < height; ++j)
                cells[i][j] = src.cells[i][j];
    }
    
    Spreadsheet::Spreadsheet(Spreadsheet &&src) noexcept
        : Spreadsheet()
    {
        src.swap(*this);
    }
    
    Spreadsheet::~Spreadsheet()
    {
        for (size_t i = 0; i < width; ++i)
            delete[] cells[i];
        delete[] cells;
    }
    
    Spreadsheet& Spreadsheet::operator=(const Spreadsheet &rhs)
    {
        if (this != &rhs)
            Spreadsheet(rhs).swap(*this);
        return *this;
    }
    
    Spreadsheet& Spreadsheet::operator=(Spreadsheet &&rhs) noexcept
    {
        rhs.swap(*this);
        return *this;
    }
    
    SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
    {
        verifyCoordinate(x, y);
        return cells[x][y];
    }
    
    void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
    {
        verifyCoordinate(x, y);
        cells[x][y] = cell;
    }
    
    void Spreadsheet::swap(Spreadsheet &other)
    {
        std::swap(cells, other.cells);
        std::swap(width, other.width);
        std::swap(height, other.height);
    }
    
    void Spreadsheet::verifyCoordinate(size_t x, size_t y) const
    {
        if (x >= width || y >= height)
            throw std::out_of_range("");
    }
    
    void swap(Spreadsheet &lhs, Spreadsheet &rhs)
    {
        lhs.swap(rhs);
    }
    

    也就是说,如果使用 std::vector 而不是原始数组:

    #pragma once
    #include "SpreadsheetCell.h"
    #include <vector>
    
    class Spreadsheet
    {
    public:
        Spreadsheet() = default;
        Spreadsheet(size_t, size_t);
        Spreadsheet(const Spreadsheet &) = default;
        Spreadsheet(Spreadsheet &&) noexcept = default;
    
        Spreadsheet& operator=(const Spreadsheet &) = default;
        Spreadsheet& operator=(Spreadsheet &&) noexcept = default;
    
        SpreadsheetCell& getCellAt(size_t, size_t);
        void setCellAt(size_t, size_t, const SpreadsheetCell&);
    
        void swap(Spreadsheet &);
    
    private:
        std::vector<std::vector<SpreadsheetCell>> cells;
    };
    
    void swap(Spreadsheet &lhs, Spreadsheet &rhs);
    

    #include "stdafx.h"
    #include "Spreadsheet.h"
    #include <utility>
    
    Spreadsheet::Spreadsheet(int width, int height)
    {
        cells.resize(width);
        for (size_t i = 0; i < width; ++i)
            cells[i].resize(height);
    }
    
    SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y)
    {
        return cells.at(x).at(y);
    }
    
    void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell)
    {
        cells.at(x).at(y) = cell;
    }
    
    void Spreadsheet::swap(Spreadsheet &other)
    {
        std::swap(cells, other.cells);
    }
    
    void swap(Spreadsheet &lhs, Spreadsheet &rhs)
    {
        lhs.swap(rhs);
    }