【问题标题】:C++ Scope Resolution IssueC++ 范围解析问题
【发布时间】:2014-03-15 14:08:22
【问题描述】:

昨天我的班级有一个实验室考试,我们必须制作一个矩阵类并重载operation+()。在我去进行单元测试之前,我认为我的做法是正确的……我知道这是很多文字;然而,我在实验室的剩余时间里试图弄清楚出了什么问题,并且无法弄清楚为什么在赋值运算符调用之前临时对象矩阵超出了范围。

代码如下:

矩阵标题

#include <iostream>
#include <iomanip>
using namespace std;
class Matrix
{
Public:
// Constructor and Destructor Suite
Matrix(int x, int y); // Lab TA stated that Matricies would never go above two dimensions
~Matrix(); 

// Access and Mutation
void set(int row, int column, int value); // This function sets the value of a given matrix coordinate at row, column to value
int get(int row, int column) const; // This function returns the value of a matrix at row, column

Matrix& operator=(const Matrix& Q)
{
    cout << "Called Assignment" << endl;
    int r, c;
    r = Q.rows; c = Q.columns;
    for (int i = 0; i < r; i++)
    {
        for (int k = 0; k < c; k++)
        {
            cout << "Address of Calling Objet pointer Int: " << this->pMatrixOfInt[i][k] << setw(5) << *this->pMatrixOfInt[i][k] << endl;
            cout << "Address of Reference Object: " << Q.pMatrixOfInt[i][k] << setw(5) << *Q.pMatrixOfInt[i][k] << endl;
            *(this->pMatrixOfInt[i][k]) = *(Q.pMatrixOfInt[i][k]);
        }
    }
    return *this;
}
const Matrix operator+(const Matrix& Q);
friend ostream& operator<<(ostream& output, const Matrix& Q);
friend istream& operator>>(istream& input, Matrix& Q);
private:
int rows, columns;
int* pMatrixOfInt[50][50]; // Specification document said that these values would never go above 50
};

Matrix.cpp

/*
Matrix Class Definition
14 March 2014
*/
#include <iomanip>
#include <iostream>
#include "Matrix.h"
// Constructor
Matrix::Matrix(int x, int y)
{
    cout << "Constructor Called" << endl;
    this->rows=x;
    this->columns=y;
    for (int i=rows-1; i>=0; i--)           // If X and Y are both 50 then the starting value
    {                                       // for i and k should be 49 because of how arrays
        for (int k=columns-1; k>=0; k--)    // are indexed. Hence the rows-1
        {
            pMatrixOfInt[i][k] = new int;
        }
    }
}
// Destructor
Matrix::~Matrix()
{
    cout << "Destructor Called" << endl;
    for (int i=rows-1; i>=0; i--)           // If X and Y are both 50 then the starting value
    {                                       // for i and k should be 49 because of how arrays
        for (int k=columns-1; k>=0; k--)    // are indexed. Hence the rows-1
        {
            delete pMatrixOfInt[i][k];
        }
    }
}
// Access and Mutation
void Matrix::set(int row, int column, int value)
{
    *pMatrixOfInt[row][column] = value;
}
int Matrix::get(int row, int column) const
{
    return *pMatrixOfInt[row][column];
}
// Overloaded Addition Operator (Possible Scope Problem)
const Matrix Matrix::operator+(const Matrix& Q)
{
    cout << "Addition Operator Called" << endl;
    int rows, columns;
    rows = Q.rows;
    columns = Q.columns;
    Matrix newMatrix(rows, columns);
    cout << "newMatrix Rows: " << newMatrix.rows << " -- newMatrix columns: " << newMatrix.columns << endl; // Make a new matrix. Constructor will initialize the pointer Matrix
    int newValue;
    for (int i=0; i<rows; i++)
    {
        for (int k=0; k<columns; k++)
        {
            newValue = this->get(i,k);
            newValue += Q.get(i,k);
            newMatrix.set(i,k, newValue);
            cout << setw(5) << newMatrix.get(i, k);
        }
        cout << "\n";
    }
    return newMatrix;
}
// Friend definitions for i/ostreams.
ostream&::operator<<(ostream& output, const Matrix& Q)
{
    for (int r = 0; r<Q.rows; r++)
    {
        for (int c = 0; c<Q.columns; c++) // hahaha
        {
            output << setw(4) << Q.get(r,c);
        }
        output << "\n";
    }
    return output;
}
istream&::operator>>(istream& input, Matrix& Q)
{
    int value;
    for (int r = 0; r<Q.rows; r++)
    {
        for (int c = 0; c<Q.columns; c++)
        {
            input >> value;
            Q.set(r,c,value);
        }
    }
    return input;
}

当我尝试做这样的事情时:

newMatrix = oldMatrixA + oldMatrixB;
cout << newMatrix;

我收到以下一系列输出,然后是 BLOCK_HEADER_ERROR:

Addition Operator Called
0   1   2   3
1   3   5   7
Destructor Called
Assignment Called
Lots of output here regarding address of calling object and value along with the reference object and value of that too
!!!BLOCK_HEADER_ERROR!!!

谁能告诉我为什么加法运算符返回的临时对象在赋值运算符之前超出范围,即使它们在同一行并且 newMatrix 是一个返回对象,因此不应该被销毁,直到调用它的作用域要求销毁它?

提前感谢您的帮助,我昨晚没睡好,因为 TA 让我上交了我知道有 bug 的工作,我一直无法找出问题所在。

我知道这是很多代码,这是我在 StackOverflow 上发布过的最长的问题;不过,我喜欢睡个好觉,在我知道出了什么问题之前,我不认为我会好好休息。

【问题讨论】:

  • 不,你做得不对:你为什么要存储指向整数而不是整数的指针? 那根本没有意义。此外,使用静态数组(即编译时大小的数组)并在运行时获取矩阵的维度也没有意义。最后,您应该使用 std::size_t 而不是整数来表示大小。
  • 另外,不要按 const 值返回!!! 这只会破坏一些可能的编译器优化。
  • 因为是实验室考试,我的手在某些方面被束缚了。这是其中之一。我只是在 C++ 编程的第一年,所以我不知道std::size_t(并且需要了解它)。至于 const 的返回,再次被束缚。

标签: c++ matrix scope operator-overloading


【解决方案1】:

为什么使用指针来存储值?改用普通整数就可以了。

首先想想“太早”的破坏:

在您的代码中,您实际上有两个临时变量(如果没有进行返回值优化): 第一个是newValue,第二个是由operator+ 返回的临时右值。

在将newValue 复制到临时右值后,newValue 被破坏(您看到的消息)。

第二个问题是:您没有指定自定义复制构造函数(想想rule of three)。因此,右值临时副本具有指向您在破坏 newValue 时释放的整数的所有指针。

如果您不能使用纯整数,那么您必须编写自己的复制构造函数来真正复制(为新矩阵分配新整数)。

如果你可以使用纯整数,那么使用它们,一切都很好(不需要自定义析构函数/复制构造函数/复制赋值运算符)

复制构造函数示例:

Matrix::Matrix(const Matrix &other) {
    this->rows=other.rows;
    this->columns=other.columns;
    for (int row = 0; row < rows; ++row) {
        for (int column = 0; column < columns; ++column) {
            // allocate a new integer with the value 
            // copied from the other matrix
            pMatrixOfInt[row][column] = new int(*other.pMatrixOfInt[row][column]);
        }
    }
}

【讨论】:

  • 正如我在回复@Manu343726 时解释的那样,我对一些可以使用的方法束手无策,因此使用int* matrixOfInt[50][50]。我不确定newValue 正在生成析构函数方法是什么意思,因为该消息仅在调用 Matrix 析构函数时生成...除非您的意思是newValue 是由operator+() 生成的临时rValue?在 Matrix.set() 中,我使用 *matrixOfInt[i][k] = newValue 来确保将 newValue 的值写入 int* 的地址。重载分配!=自定义副本??
  • 那你需要实现拷贝构造函数和拷贝赋值否则你的代码是错误的。编译器所做的默认复制操作不合适,会导致您的情况出现错误。
  • newValueoperator+ 返回时超出范围,因此在其上调用析构函数。您需要区分operator=(据我所见,您明确使用并正确实现)和复制构造函数Matrix(const Matrix&amp;),它被隐式调用以将newValue的值返回到operator+的临时返回值中
  • 这可能是我的代码无法正常工作的原因!我没有学过复制构造函数,也不知道如何编写一个。我正在查看那个维基百科条目并试图理解它(并且失败了)。如果问得不算多,您能否在原始答案中写一个简短的复制构造函数示例,以便我选择它?
  • 我很确定,您将能够自己完成此操作。复制构造函数基本上是构造函数和复制赋值的混合体。我还是会发布一个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 2010-10-11
  • 2019-06-17
  • 2015-10-12
  • 2016-06-21
  • 2011-07-07
相关资源
最近更新 更多