template <typename T>
class Table {
public:
Table();
Table(int m, int n);
Table(int m, int n, const T& value);
Table(const Table<T>& rhs);
~Table();
Table<T>& operator=(const Table& rhs);
T& operator()(int i, int j);
int numRows()const;
int numCols()const;
void resize(int m, int n);
void resize(int m, int n, const T& value);
private:
// Make private because this method should only be used
// internally by the class.
void destroy();
private:
int mNumRows;
int mNumCols;
T** mDataMatrix;
};
template <typename T>
void Table<T>::destroy() {
// Does the matrix exist?
if (mDataMatrix) {
for (int i = 0; i < _m; ++i) {
// Does the ith row exist?
if (mDataMatrix[i]) {
// Yes, delete it.
delete[]mDataMatrix[i];
mDataMatrix[i] = 0;
}
}
// Delete the row-array.
delete[] mDataMatrix;
mDataMatrix = 0;
}
mNumRows = 0;
mNumCols = 0;
}
这是我从一本书中获得的代码示例。它演示了如何破坏或释放2x2矩阵,其中mDataMatrix是指向指针数组的指针。
我不明白的是这一部分:
for(int i = 0; i < _m; ++i) {
// Does the ith row exist?
if (mDataMatrix[i]) {
//.….
}
}
我不知道为什么这本书使用_m作为最大行数-ptr。它甚至不是课堂上的变量定义; max row的变量是mNumRows。也许它是一些编译器预定义的变量?我很困惑的另一件事是为什么它是++ i?前算子,为什么不是i ++?如果我把它改成i ++会不会有所不同?
答案 0 :(得分:5)
另一件我很困惑的事情是为什么它是++ i?前算子,为什么不是i ++?如果我把它改成i ++会不会有所不同?
因为++i
更自然且更容易理解:增加i
然后产生变量i
。另一方面,i++
表示将i
的当前值复制到某处(让我们称之为temp
),增加i
,然后将值temp
复制为结果。
此外,对于用户定义的类型,i++
可能比++i
慢。
请注意,++i
作为循环增量不暗示增量在进入循环体之前发生。 (这似乎是初学者中常见的误解。)如果你没有使用++i
或i++
作为更大表达式的一部分,那么语义完全相同,因为前缀和后缀增量只是不同在结果(增量变量与旧值)中,而不是在副作用中(递增变量)。
答案 1 :(得分:3)
在没有看到整个类代码的情况下,很难说出你的第一个问题,但是如果它没有被定义为类的一部分,我的猜测是它是一个错字。
关于第二个问题,++ i与i ++,前缀增量运算符(++ i)返回正在递增的对象,而后缀增量运算符返回对象的原始状态的副本。即.-
int i=1;
std::cout << i++ << std::endl; // output: 1
std::cout << i << std::endl // output: 2
std::cout << ++i << std::endl // output: 3
至于代码是否会随后缀更改 - 否,它在循环中的工作方式相同,并且在整数类型的循环中基本没有区别。但是,对于用户定义的类型,使用前缀增量可能更有效,并且是许多c ++程序员默认使用的样式。
答案 2 :(得分:2)
如果_m
变量未在任何地方定义,则这是一个错误。从该上下文看起来它应该包含在某处分配new
的行数(可能在构造函数中,或者可能有像addRow
这样的方法)。如果该数字始终为mNumRows
,那么这将适用于析构函数中的循环。
如果您使用++i
或i++
,则for循环没有任何区别。两种变体都会递增整数,并且表达式的返回值(可能会有所不同)不会在任何地方使用。
答案 3 :(得分:0)
我不能谈论问题的第一部分,但我可以解释前后增加的困境。
前缀版本的递增和递减稍微提高效率,通常是首选。但最后,除非循环执行很多次,否则使用i ++ over ++ i引起的额外开销可以忽略不计。
答案 4 :(得分:0)
正如其他人所说,在处理用户定义的类型时,出于性能原因,首选运算符是首选。它对for
循环没有影响的原因是因为涉及变量值的测试(即i < _m)
是在执行修改变量的操作之前执行的。
答案 5 :(得分:0)
本书真正的混乱是它说明2x2矩阵的方式。问题在于,对于4个元素,你分配了3块内存,这不仅会减慢程序的速度,而且处理起来肯定要棘手。
通常的技术要简单得多:
T* mData = new T[2*2];
然后你这样访问它:
T& operator()(size_t r, size_t c) { return mData[r * mNbRows + c]; }
这是一项更多工作(如果你是行专业,你必须乘以行数),但destroy
非常容易:
template <class T>
void Table<T>::destroy()
{
delete[] mData;
mData = 0;
mNbRows = 0;
mNbColumns = 0;
}
另请注意,此处不需要if
:可以在空指针上调用delete
,它只是不执行任何操作。
最后,我不知道为什么你的书使用int
作为坐标,负坐标在这个Table
类的上下文中是否有任何意义?如果没有,你最好使用无符号整数类型(如size_t
)并扔掉书。