移动构造函数错误并使用移动构造函数委派

时间:2018-06-16 04:20:56

标签: c++ constructor move-semantics move-constructor

为什么移动赋值运算符的此实现会在附加图像中给出错误

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

我附上了全部资源。

Spreadsheet类定义 SPreadsheet.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;
};

Spreadsheet类实现 Spreadsheet.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;
};

SpreadsheetCell类定义 SPreadsheetCell.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类实现

Spreadsheetcell.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 个答案:

答案 0 :(得分:1)

您的代码中有几个逻辑错误:

  • 您的分配构造函数未正确循环遍历第一维数组。您正在分配一个具有public class Program { public static void Main(string[] args) { Drawing myDrawing3D = new Drawing3D("Sketch 3D", 10, 12, 14); myDrawing3D.Print(); Drawing myDrawing2D = new Drawing2D("Sketch 2D", 10, 12); myDrawing2D.Print(); Console.WriteLine("Done"); } } 个元素数的数组,然后循环遍历它,就像它具有width个元素一样。如果height,则超出数组的范围并损坏内存。如果是width < height,则不会填充整个数组,而是使用不确定值的指针。

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

  • 您的width > height未正确切换。 swap()的目的是将两个对象的内容相互交换,但是您的输入参数是按值传递的,因此传递给它的任何对象都会先被复制,然后您将与复制的对象进行交换,不是原始对象。原始对象不变。因此,您必须通过引用传递参数。

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

尝试更像这样的东西:

swap()

#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);