2013-03-14 61 views
0

我正在阅读一本关于Safe C++的书。这里的作者提到如何避免出现数组读取的问题。这里提到了我们如何避免多维数组的数组读取问题。这里的作者使用了operator()函数,如下面的链接所示,而不是operator [],并给出了下面的解释。这里多维数组超出范围检查

https://github.com/vladimir-kushnir/SafeCPlusPlus/blob/master/scpp_matrix.hpp

注意要访问多维数组,我们要么需要使用多个[]运营商,如矩阵[i] [j],或单()运算符,如基质(I,J )。

如果我们让[]运算符返回一个指向第i行第零元素的T *指针,则可以实现第一种方法。但是,这否定了列索引超出范围的诊断,这违背了在运行时捕获错误的目的。当然,我们可以创建一些模板类,这会增加对行的智能引用,返回使用第一个运算符([i])的实例,然后使用第二个运算符(j)中的边界检查)。

我的问题是什么笔者通过“意味着创造一些模板类,它会incldue智能引用到行,返回使用第一运营实例([1]),然后使用边界检查第二运算符(j))“。?请求提供示例代码,了解如何在C++中实现上述逻辑?

感谢您的时间和帮助。

+2

您能不能通过您的努力启发我们 – 2013-03-14 05:31:11

+0

当问题是“这意味着什么”时,到目前为止还有什么努力? – FoolishSeth 2013-03-14 05:32:43

+1

作者意味着你返回一个包含嵌入引用的对象,该嵌入引用指向索引行的开始,并且在该对象内的大小限制,以便覆盖'operator []'的边界(对象)可以边界检查索引该维度类似于第一个维度被编入索引。 – WhozCraig 2013-03-14 05:36:33

回答

3

的基本思路看起来是这样的:

#include <vector> 
#include <iostream> 

template <class T> 
class matrix { 
    size_t cols; 
    size_t rows; 
    std::vector<T> data; 

    class row_proxy { // This class is the part the question really asked about 
     size_t row; 
     matrix &m; 
    public: 
     row_proxy(matrix &m, size_t row) : row(row), m(m) {} 

     T &operator[](size_t col) { 
      if (row > m.rows || col > m.cols) 
       throw std::logic_error("Bad index"); 
      return m.data[row * m.cols + col]; 
     } 
    }; 

public: 

    matrix(size_t cols, size_t rows) : rows(rows), cols(cols), data(rows*cols) {} 

    row_proxy operator[](size_t row) { 
     return row_proxy(*this, row); 
    } 
}; 

int main() { 
    matrix<int> m(3, 3); 

    for (int i=0; i<3; i++) // fill the matrix with identifiable numbers 
     for (int j=0; j<3; j++) 
      m[i][j] = i * 100 + j; 

    for (int i=0; i<3; i++) { // show the content 
     for (int j=0; j<3; j++) 
      std::cout << m[i][j] << "\t"; 
     std::cout << "\n"; 
    } 

    try {      // test the bounds checking. 
     m[4][1] = 21; 
    } 
    catch(std::logic_error &e) { 
     std::cerr << e.what(); 
    } 

    return 0; 
} 

所以,当我们创建了一个矩阵,我们保存它的大小在rowscols。当我们在矩阵上使用operator[]时,它不会尝试直接返回对矩阵中某个项的引用 - 而是返回一个代理类的实例,用于跟踪行和矩阵,提供自己的operator[]

因此,当您使用matrix[a][b]时,第一个将amatrix保存到代理对象中。然后在该代理对象上调用[b]部分。这将检查ab是否在我们为矩阵保存的范围内,如果是,则返回对矢量中正确对象的引用。否则,它会抛出一个std::Logic_error(可能不是最好的选择 - 只是第一次发生在我身上)。

我应该补充说,这个总体思路有很多变化。仅举一个例子,您可以在编译时指定数组的大小,但将大小作为模板参数传递。这可以有一些优点 - 例如,matrix<int, 2, 3>matrix<int, 3, 2>是完全不同的类型,所以您不能意外地将一个指派给另一个。它也可能有一些缺点(最明显的是,你需要需要来知道编译时的大小,否则根本不会工作)。

+0

感谢您的详细解释。现在我明白了作者的意思。 – venkysmarty 2013-03-14 08:12:52