C++具有自定义类的动态 2D 数组
C++ Dynamic 2D Array with Custom Classes
该程序的目标是从一维数组类创建一个复合二维数组类,利用指针和operator[]
在主程序中使用。我们被告知要让[][]
像标准2D阵列一样工作。我让它编译,但当我使用 2DArray
类时它崩溃了。我知道目标是理解指针,但我认为运算符[]给我带来了最大的麻烦。任何见解将不胜感激。
编辑:适用于标准数组。但是,如果我能以简单的方式使用该类,我会很高兴,例如:
#include <iostream>
#include "MyArray.h"
#include "TwoDArray.h"
using namespace std;
int main()
{
TwoDArray test(4,5);
cout << "Test output: "<< test[3][2] << endl;
return 0;
}
下面是 2D 数组类实现的代码:
#include <iostream>
#include <cstdlib>
#include "TwoDArray.h"
#include "MyArray.h"
TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
MyArray** p = new MyArray* [10];
for (int i = 0; i < 10; i++)
{
p[i] = new MyArray[10];
}
}
TwoDArray::TwoDArray (int r, int c)
{
row = r;
col = c;
MyArray** p = new MyArray* [col];
for (int i = 0; i < col; i++)
{
p[i] = new MyArray[row];
}
}
TwoDArray::~TwoDArray() //Destructor
{
for (int i = 0; i < row; i++)
{
delete [] &p[i];
}
delete [] p;
}
MyArray & TwoDArray::operator[] (int pos)
{
if( pos < 0 || pos >= col )
{
cout << "Illegal index, pos = " << pos << endl;
}
return *p[pos];
}
以及讲师给出的 1DArray (MyArray( 类实现:
#include <iostream>
#include <cstdlib>
#include "MyArray.h" // "" around header means "look in current directory first"
// default to an array of 10 integers, fill with 0
MyArray::MyArray()
{
int i;
_a = new int[10]; // new allocates RAM from system heap, [] says allocate an array
_n = 10;
for( i = 0; i < 10; i++ )
{
_a[i] = 0; // initialize array to all 0
}
}
// allocate array of a size requested by the client if legal, fill with 0
MyArray::MyArray( int num )
{
int i;
if( num <= 0 ) // if illegal, set to default
{
num = 10;
}
_a = new int[num];
_n = num;
for( i = 0; i < num; i++ )
{
_a[i] = 0; // initialize array to all 0
}
}
// copy constructor - invoke deep copy asignment
MyArray::MyArray( const MyArray &m )
{
*this = m;
}
// destructor - needed to deallocate RAM allocated in constructors
MyArray::~MyArray()
{
delete[] _a;
}
// get value at position pos
int &MyArray::At( int pos )
{
if( pos < 0 || pos >= _n )
{
cout << "Illegal index, pos = " << pos << endl;
exit( -1 );
}
return _a[pos];
}
// get value at position pos using [] indexing operator
int & MyArray::operator []( int pos )
{
cout << "1D [] pos = " << pos << "_n is " << _n << endl;
if( pos < 0 || pos >= _n )
{
cout << "Illegal index, pos = " << pos << endl;
exit( -1 );
}
return _a[pos];
}
// return size, const here means it cannot change self
int MyArray::size( void ) const
{
return _n;
}
// deep copy - REQUIRED if allocated RAM is used by object!
MyArray &MyArray::operator =( const MyArray &rhs )
{
int i;
if( &rhs == this ) // assignment to self?
{
return *this; // if so, don't assign, just return self
}
if( rhs._n != _n ) // rhs not the same size as myself?
{
delete[] _a; // yes, clear out my data and reallocate to match
_a = new int[rhs._n];
_n = rhs._n;
}
for( i = 0; i < rhs._n; i++ ) // copy all elements
{
_a[i] = rhs._a[i];
}
return *this; // allow a = b = c; assignment
}
如果MyArray
本身是一个一维数组,那么你做错了我用MyArray
初始化二维数组。我不是在描述细节,但我认为你需要做这样的事情——
TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
MyArray* p = new MyArray [10];
for (int i = 0; i < 10; i++)
{
p[i] = new MyArray(10);
} }
TwoDArray::TwoDArray (int r, int c)
{
row = r;
col = c;
MyArray* p = new MyArray [col];
for (int i = 0; i < col; i++)
{
p[i] = new MyArray(row);
}
}
请注意,我用一个 1D 数组更改了 2D 初始化,每个数组内部都是一个 MyArray
对象,而该对象本身就是一个数组 - 因此 2D 数组
你的析构函数有点想多了。试试这个:
TwoDArray::~TwoDArray() //Destructor
{
delete [] p;
}
您也不会在构造函数中存储分配的指针。您正在将分配的内存分配给您在堆栈上声明的指针。不是您的会员p
此外,您正在分配一个 2D 数组数组,这将构成一个 3D 数组
在您的构造函数中,将您的成员p
一个MyArray
数组,如下所示:
TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
p = new MyArray[row]; // where p is a MyArray* member of TwoDArray
for (int i = 0; i < row; i++)
{
p[i] = MyArray(col);
}
}
TwoDArray::TwoDArray (int r, int c)
{
row = r;
col = c;
p = new MyArray[row]; // where p is a MyArray* member of TwoDArray
for (int i = 0; i < row; i++)
{
p[i] = MyArray(col);
}
}
您的代码仍然存在一些问题。
Issue 1:
如果 TwoDArray 是一个 const 对象,你的运算符 [] 将不会编译。 这是一个例子
void foo(const TwoDArray& arr)
{
int x = arr[0][0]; // error. operator [] must be const
}
在这里有一个 const TwoDArray 是完全合理的,因为你没有改变数组的内部结构。 因此,您需要重载运算符 [] 两次,一次用于常量对象,另一次用于非常量对象。 所以第二个重载应该看起来像这样:
const MyArray & TwoDArray::operator[] (int pos) const
{
if( pos < 0 || pos >= col )
{
cout << "Illegal index, pos = " << pos << endl;
}
return *p[pos];
}
但是,这里仍然存在一个问题,我将在下面的Issue 3
中展示。
Issue 2:
如果分配运算符失败,new[]
将损坏this
。
在赋值运算符中,调用 delete[] _a
。 如果后续对new []
调用引发异常,会发生什么情况? 您现在已经损坏了对象,因为您删除了内存,因此无法恢复已删除的数据。
至少在你的实现中,应该做的是
- 首先分配新内存,然后分配给临时指针,
- 将数据从传入的对象移动到新内存,
- 删除旧内存(在这种情况下,这是您最终调用
delete [] _a;
的地方( - 将步骤 1 中的临时指针分配给
_a
。
这样,如果步骤 1 失败,将引发异常,并且您的对象不会损坏。
Issue 3:
在您的operator []
中,如果完成了越界访问,您仍然会继续执行非法访问。
如果你想让类的用户在他们提供越界访问权限时搬起石头砸自己的脚,那么我认为你应该删除cout
消息并继续允许非法访问。 如果您确实想要边界检查访问,请使用 at(( 函数,该函数可以输出和throw an exception
越界访问。
请注意,这就是std::vector
做事的方式 - operator []
未选中,而std::vector::at()
被选中并会抛出错误。
Issue 4:
. 样式 -- 注意变量名称开头带有下划线。
带下划线的名称是为编译器的实现保留的。 我知道在某些情况下,带下划线的名称是安全的,但我总是谨慎行事,从不引入以下划线开头的名称。
Issue 5:
你想有一个使用运算符 [] 的 2D 数组吗?
有人反对使用 [][] 来表示二维矩阵,而是让operator()
表示索引。
看这里: http://www.parashift.com/c++-faq/matrix-subscript-op.html
你的 TwoDArray 构造函数在这里是有缺陷的: for (int i = 0; i <10; i++( { p[i] = new MyArray[10]; }
您实际上正在创建一个 3D 数组!!将其更改为 p[i] = new MyArray(10(;
然后从那里继续!
如果我理解正确的代码,MyArray
代表一行TwoDArray
。在这种情况下,TwoDArray
的构造函数不会使用正确的参数创建MyArray
对象。
你有:
TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
MyArray** p = new MyArray* [10];
for (int i = 0; i < 10; i++)
{
p[i] = new MyArray[10];
}
}
首先,我会将10
的使用更改为适当地使用row
和col
。
TwoDArray::TwoDArray()
{
//Default Constructor
row = 10;
col = 10;
MyArray** p = new MyArray* [row];
for (int i = 0; i < 10; i++)
{
p[i] = new MyArray[col]; // This is a problem line. You are creating col
// MyArray objects. I think you should create one
// MyArray object with col items in it.
p[i] = new MyArray(col); // This is what you want.
}
}
但真正的问题是你有:
MyArray** p = new MyArray* [row];
这是一个局部变量。当您从函数返回时,它会消失。成员变量p
保持未初始化状态。您可能的意思是:
p = new MyArray* [row];
您可以类似地更改其他构造函数。
CPPGy已经指出了析构函数的问题。
- 这是使用回溯的 nqueen 问题,但我使用了动态 2d 数组,我的程序编译良好,但不返回任何输出
- 检测到堆损坏:在正常块 c++ 动态 2D 数组之后
- 动态 2D 阵列.为什么分段错误?
- 不使用新的动态2D阵列
- 为什么我们在传递动态 2D 数组时不需要列数?
- 如何解决在使用动态 2D 数组进行矩阵乘法的 MPI 进行并行编程时的问题
- C++ 在类中删除动态 2D 数组时不断"Aborted (core dumped)"
- 如何在不使用指针的情况下将动态2D数组传递到函数
- 如何从文件中读取并将内容存储在动态 2D 数组中并以网格格式显示
- 如何在使用动态 2D 数组时修复此代码
- 创建一个动态2D数组来存储类对象
- 访问动态 2D 字符数组时引发访问冲突异常
- 在动态2D布尔数组中更改一个值似乎会更改不同数组中不同位置的值
- 动态2D阵列访问侵犯剩余
- C++动态 2D 阵列
- OpenGL 渲染大量动态 2D 圆
- 在 C++ 中销毁指向动态 2D 数组的指针
- 正在从CIN声明动态2D阵列
- c++中动态2d字符串数组的解除分配
- 无法在C++中声明动态 2D 数组