三法则练习意外结果 [重复]

rule of three exercise unexpected result [duplicate]

提问人:newbie 提问时间:9/3/2015 最后编辑:newbie 更新时间:9/3/2015 访问量:221

问:

我尝试在空闲时间学习C++基础,并遵循书本的练习。首先,当我输入 9 作为行和 8 作为列时,我得到 malloc 释放错误。其次,我得到 0 作为输出,我看不到我输入的内容。我想编写程序,因为我可以强化三法则。这当然不是家庭作业。此外,我认为这是很难的问题和有效的问题。如果这个问题可以得到回答,那将是有帮助的。因为我在谷歌上搜索过,所以我找不到关于解决方案的一半体面的事情。另外,你能检查我的复制构造函数、赋值运算符和析构函数并告诉我我的错误在哪里吗?

编写一个实现二维动态数组的类 TwoD 的双打在其构造函数中使用此显示中的想法。你 应该有一个 pointer 类型的私有成员,要将 double 指向 动态数组和两个 int(或无符号 int)值 MaxRows 和 MaxCols。您应该提供一个默认构造函数,其 您将选择默认的最大行和列大小以及 参数化构造函数,允许程序员设置最大值 行和列大小。此外,您还应提供一个 void 成员 允许设置分词行和列条目的功能,以及 成员函数,该函数将特定行和列条目作为 double 类型的值。备注:这很困难或不可能(取决于 在细节上)重载 [ ] ,以便它按您的意愿工作 二维数组。因此,只需使用访问器和变值器函数即可 使用普通函数表示法。将 + 运算符重载为友元 函数添加两个二维数组。此函数应 返回第 i 行第 j 列元素的 TwoD 对象,该对象是 左操作数 TwoD 对象的第 i 行、第 j 列元素 和右边操作数 TwoD 的第 i 行、第 j 列元素 对象。提供一个复制构造函数、一个重载运算符 = 和一个 破坏者。声明不更改数据的类成员函数 作为 const 成员。

我的努力

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

class TwoD
{
public:
    TwoD();
    TwoD(int row, int column);
    void setRowCol();
    double getVal(int row, int column);
    friend const TwoD operator +(const TwoD& first, const TwoD& second);
    int getterRow() const;
    int getterCol() const;
    void setterRow(int row);
    void setterCol(int column);
    TwoD(const TwoD& object);
    TwoD& operator =(const TwoD& rightSide);
    void putArr() const;
    ~TwoD();
    static TwoD constructFromUserInput();
private:
    int MaxRows;
    int MaxCols;
    double **arr;
};

int main(int argc, char const *argv[])
{
    cout << "All size of TwoD object must be same\n\n";

    TwoD arr1 = TwoD::constructFromUserInput();
    TwoD arr2 = TwoD::constructFromUserInput();

    TwoD arr3;

    arr3 = arr1 + arr2;

    TwoD arr4(arr3);
    arr1.putArr();
    arr2.putArr();
    arr3.putArr();
    arr4.putArr();

    return 0;
}
void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    MaxRows = r_user;
    MaxCols = c_user;

    TwoD(MaxRows,MaxCols);

}
TwoD::TwoD(int row, int column)
: MaxRows(row), MaxCols(column)
{
    arr = new double*[row];
    for (int i = 0; i < row; i++)
    {
        arr[i] = new double[column];
    }

    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> arr[i][j];
        }
    }
}
TwoD::TwoD()
: MaxRows(2), MaxCols(2)
{
    arr = new double*[2];
    for (int i = 0; i < 2; i++)
    {
        arr[i] = new double[2];
    }
}
double TwoD::getVal(int row, int column)
{
    return arr[row][column];
}
const TwoD operator +(const TwoD& first, const TwoD& second)
{
    TwoD sum;
    for (int i = 0; i < first.MaxRows; i++)
    {
        for (int j = 0; j < first.MaxCols; j++)
        {
            sum.arr[i][j] = first.arr[i][j] + second.arr[i][j];
        }
    }
    return sum;
}
TwoD::TwoD(const TwoD& object)
{
    MaxRows = object.MaxRows;
    MaxCols = object.MaxCols;

    arr = new double*[MaxRows];
    for (int i = 0; i < MaxRows; i++)
    {
        arr[i] = new double[MaxCols];
    }

    for ( int i = 0; i < MaxRows; i++ )
    {
        for ( int j = 0; j < MaxCols; j++ )
        {
            arr[i][j] = object.arr[i][j];
        }
    }
}
TwoD::~TwoD()
{
    for (int i = 0; i < MaxRows; i++)
        delete [] arr[i];
    delete [] arr;
}
TwoD& TwoD::operator =(const TwoD& rightSide)
{
    if (this == &rightSide)
    {
        return *this;
    }

    for (int i = 0; i < MaxRows; i++)
        delete [] arr[i];
    delete [] arr;

    arr = new double*[rightSide.MaxRows];
    for (int i = 0; i < rightSide.MaxRows; i++)
    {
        arr[i] = new double[rightSide.MaxCols];
    }

    MaxRows = rightSide.MaxRows;
    MaxCols = rightSide.MaxCols;

    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            arr[i][j] = rightSide.arr[i][j];
        }
    }
    return *this;
}
void TwoD::putArr() const
{
    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}
int TwoD::getterRow() const
{
    return MaxRows;
}
int TwoD::getterCol() const
{
    return MaxCols;
}
void TwoD::setterRow(int row)
{
    MaxRows = row;
}
void TwoD::setterCol(int column)
{
    MaxCols = column;
}
TwoD TwoD::constructFromUserInput()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Construct an object.
    TwoD obj(r_user, c_user);

    // Return the object
    return obj;
}
C++ 指针动态 内存分配 三法则

评论

5赞 πάντα ῥεῖ 9/3/2015
我们已经有一个很好的问答,关于如何正确实施和应用 3 规则

答:

2赞 Useless 9/3/2015 #1
  1. 复制构造函数创建数组,但从不复制内容。 复制赋值运算符可以正确地执行此操作。就此而言,你有大量的重复循环,几个循环,你应该有两个复制循环。将这些因素分解为函数,您只需要将它们正确一次。new[]delete[]

  2. sum创建一个默认大小的对象,然后可能会超出行和列的维度。通常的(简单而正确的)实现是创建左侧参数的本地副本(使用上面修复的复制 ctor)并转发到 。该运算符更容易正确。operator+=

  3. 你有办法把这些矩阵打印出来。做吧!到处都做!这样可以很容易地看出哪个阶段出了问题。

  4. 这本书听起来不太好。它无缘无故地教授糟糕的实践(运算符+技巧是标准的,如果你不能使用,你应该使用,等等。unique_ptrvector


编辑:我会在这里回复一些评论,因为它们有变成聊天会话的危险,我不想花更多的时间在这上面。

  • 我有固定的复制构造函数,对吗?

    这是弄清楚如何测试和调试代码的好时机。添加 print 语句,使用调试器,将内容拆分为可以测试的函数,然后为它们编写测试。

  • 你的意思是几个循环和两个复制循环delete[]

    在代码中查找循环。我可以看到 3 个循环调用,它们基本上都在做同样的事情。我可以看到 2 个循环调用,一个在析构函数中,一个在复制赋值运算符中。只需在您自己的代码中搜索关键字即可!new[]delete[]for

  • 我真的找不到打印矩阵的方法

    那么从哪里来呢?诚然,它的名字会更好,但你写了它,所以你不妨使用它。TwoD::putArrostream& operator<<(ostream&, TwoD const &)

  • 我无法将析构函数放入 main()

    当 Main 结束时,您无法停止调用析构函数 - 然后您的对象就超出了范围。只需在析构函数中插入一个断点,它就会被调用。

  • 因为 arr 是私有的,我该如何测试?

    你仍然可以在调试器中看到它,你仍然可以打印内容(如上所述),你仍然可以从单元测试中调用,你可以一直做,直到你弄清楚你的问题getValpublic

评论

0赞 newbie 9/3/2015
你推荐哪本书?这绝对是 c++ 沃尔特·萨维奇
0赞 Useless 9/3/2015
恐怕书籍推荐是OT,反正我不知道该推销什么级别。只需从评论中的 3 规则链接开始,然后进行自己的研究。
0赞 newbie 9/3/2015
对于第一个规范,我有固定的复制构造函数,对吗?还有一件事我不明白你的意思:几个循环和两个复制循环。你介意解释一下吗?我已经有析构函数了。delete[]
0赞 Useless 9/3/2015
你拆解了 dtor 和赋值运算符中的数组,复制了代码。将其移动到函数并从两个位置调用。分配数组相同,复制值相同。
0赞 Useless 9/3/2015
哦,这是对的吗?测试一下!打印结果,在调试器中单步执行,看看它是否执行正确的操作。
0赞 R Sahu 9/3/2015 #2

代码问题:

void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    MaxRows = r_user;
    MaxCols = c_user;

    ///
    /// This constructs a new TwoD object but does not change
    /// object on which the function was invoked.
    ///
    TwoD(MaxRows,MaxCols);    
}

解决问题的方法:

更新成员数据

void TwoD::setRowCol()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Delete the current memory
    for (int i = 0; i < MaxRows; i++)
    {
       delete [] arr[i];
    }

    delete [] arr;

    MaxRows = r_user;
    MaxCols = c_user;

    // Allocate new memory.
    arr = new double*[MaxRows];
    for (int i = 0; i < MaxRows; i++)
    {
       arr[i] = new double[MaxCols];
    }

    // Now read the data.
    for (int i = 0; i < MaxRows; i++)
    {
        for (int j = 0; j < MaxCols; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> arr[i][j];
        }
    }
}

创建一个返回全新对象的函数

我推荐这种方法。

首先,更新采用行和列的构造函数,使其没有任何代码从用户输入中读取数据。

TwoD::TwoD(int row, int column)
: MaxRows(row), MaxCols(column)
{
    arr = new double*[row];
    for (int i = 0; i < row; i++)
    {
        arr[i] = new double[column];
    }
}

其次,添加一个成员函数以从用户输入构造对象。static

static TwoD constructFromUserInput();

并按以下方式实现:

TwoD TwoD::constructFromUserInput()
{
    int r_user;
    int c_user;
    cout << "Enter num of rows => ";
    cin  >> r_user;
    cout << "Enter num of columns => ";
    cin  >> c_user;

    // Construct an object.
    TwoD obj(r_user, c_user);

    // Now read the data.
    for (int i = 0; i < r_user; i++)
    {
        for (int j = 0; j < c_user; j++)
        {
            cout << "Enter for " << i << j << "=> ";
            cin  >> obj.arr[i][j];
        }
    }

    // Return the object
    return obj;
}

第三,使用 .main

int main(int argc, char const *argv[])
{
   cout << "All size of TwoD object must be same\n\n";

   TwoD arr1 = TwoD::constructFromUserInput();
   TwoD arr2 = TwoD::constructFromUserInput();

   TwoD arr3;

   arr3 = arr1 + arr2;
   arr1.putArr();
   arr2.putArr();
   arr3.putArr();

   return 0;
}

评论

0赞 newbie 9/3/2015
感谢您在应用您建议的方式后,我也尝试复制构造函数,我遇到内存错误。.你介意帮忙吗?我更新了代码。TwoD arr4(arr3);
0赞 R Sahu 9/3/2015
@newbie,这条线是错误的。您最终会越界使用数组。它必须是 .for ( int i = 0; i < MaxRows + 1; i++ )for ( int i = 0; i < MaxRows; i++ )
0赞 R Sahu 9/3/2015
@newbie,尝试使用注释和响应调试代码并不是很有成效。在代码中自由地放置语句以跟踪问题;cout
0赞 newbie 9/3/2015
我已经使用并得到错误。我找不到。如果世界上有天堂,那就是亨迪斯坦。const TwoD operator +(const TwoD& first, const TwoD& second)