【问题标题】:move constructor error and delegating using a move constructor [closed]移动构造函数错误并使用移动构造函数进行委派[关闭]
【发布时间】:2018-06-16 04:20:55
【问题描述】:

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

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

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

【问题讨论】:

  • 应该delete[] cells[i]; 是delete cells[i] 吗?在没有完整来源的情况下,这对我来说是最可疑的行。
  • @Stephano NO 单元格 def 是 cells = new SpreadsheetCell*[width]; for (size_t i = 0; i &lt; height; i++) cells[i] = new SpreadsheetCell[height];而且资源很长,在提供移动构造函数和赋值运算符之前代码运行良好
  • 我们需要查看cells 的任何类型的声明。还有Spreadsheet 中cells 成员的声明。请不要让我们玩猜谜游戏。
  • @PaulSanders 单元格是 SpreadsheetCell 类型的指针,这是 Spreadsheet.h 中的声明 SpreadsheetCell** cells = nullptr;
  • @AsmM 那个循环是错误的。它应该使用i &lt; width 而不是i &lt; height。

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


【解决方案1】:

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

  • 您的分配构造函数未正确循环通过一维数组。您正在分配具有 width 元素数量的数组,然后循环遍历它,就好像它具有 height 元素数量一样。如果width &lt; height,则超出了数组的界限并损坏了内存。如果width &gt; 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);

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

【讨论】:

  • 我想知道错误的原因。我可以更改代码。我们不应该考虑大型对象的开销吗(不是我的情况)
  • @AsmM 你的代码中有几个逻辑错误
  • 我在等着认识他们
  • @AsmM 查看我的其他 cmets
  • 是的,你说得对。我现在看到了,谢谢。我用了两次高度,其中一次用的是宽度。
猜你喜欢
  • 2011-05-22
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多