这本书错了吗?

时间:2010-07-14 12:19:19

标签: c++

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 ++会不会有所不同?

6 个答案:

答案 0 :(得分:5)

  

另一件我很困惑的事情是为什么它是++ i?前算子,为什么不是i ++?如果我把它改成i ++会不会有所不同?

因为++i更自然且更容易理解:增加i然后产生变量i。另一方面,i++表示将i的当前值复制到某处(让我们称之为temp),增加i,然后将值temp复制为结果。

此外,对于用户定义的类型,i++可能比++i慢。

请注意,++i作为循环增量暗示增量在进入循环体之前发生。 (这似乎是初学者中常见的误解。)如果你没有使用++ii++作为更大表达式的一部分,那么语义完全相同,因为前缀和后缀增量只是不同在结果(增量变量与旧值)中,而不是在副作用中(递增变量)。

答案 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,那么这将适用于析构函数中的循环。

如果您使用++ii++,则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)并扔掉书。