三、索引越界
1、动态数组可以使用new,也可以用vector来动态创建
但是当下标的索引超过size的时候,new出来的数组对其进行更改的时候会有不确定的错误产生;vector提供了一个at(index)的函数,他通过抛出一个out_of_range异常执行边界检测
测试代码(vs2012+win7环境):
#include "stdafx.h"
#include "scpp_assert.h"
#include "iostream"
#include "vector"
#define SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
char *str = new char[SIZE];
str[SIZE + 1] = 'x';
std::vector<char> arrayStr;
arrayStr.resize(SIZE);
arrayStr[11] = 'x';
return 0;
}
他的问题在于如果我们想执行这种安全检查,必须在访问数组元素的每个地方都严格地使用at()函数。显然这种做法会降低代码的效率,因此在完成了测试之后,我们可能想要速度更快的[]操作符在每处对他继续拧替换。但是,这样的替换对代码进行大量的修改。因此可以使用下面的方法(以解决不必使用at函数):
#ifndef __SCPP_VECTOR_H__
#define __SCPP_VECTOR_H__
#include "scpp_assert.h"
#include "vector"
namespace scpp
{
template <typename T>
class vector : public std::vector<T>
{
public:
typedef unsigned size_type;
public:
explicit vector(size_type n = 0) : std::vector<T>(n){ }
vector(size_type n, const T& value) : std::vector<T>(n, value){ }
template <class InputIterator> vector(InputIterator first, InputIterator last)
: std::vector<T>(first, last){ }
T &operator[] (size_type index)
{
SCPP_TEST_ASSERT(index < std::vector<T>::size(),
"Index " << index << " must be less than "
<< std::vector<T>::size());
return std::vector<T>::operator [](index);
}
const T &operator[] (size_type index) const
{
SCPP_TEST_ASSERT(index < std::vector<T>::size(),
"Index " << index << " must be less than "
<< std::vector<T>::size());
return std::vector<T>::operator [](index);
}
};
}; // namespace scpp
template <typename T>
inline std::ostream &operator << (std::ostream &os, const scpp::vector<T>& v)
{
for (unsigned index = 0; index < v.size(); ++index)
{
os << v[index];
if (index + 1 < v.size())
{
os << " ";
}
}
return os;
}
#endif
测试代码(vs2012+win7环境):
#include "stdafx.h"
#include "scpp_assert.h"
#include "iostream"
#include "scpp_vector.h"
#define SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
scpp::vector<char> str(SIZE, 'z');
std::cout << str << std::endl;
str[20] = 'x';
return 0;
}
在stdafx.h中打开调试开关:
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: 在此处引用程序需要的其他头文件
/*#define SCPP_THROW_EXCEPTION_ON_BUG*/
#define SCPP_TEST_ASSERT_ON
2、静态数组:
scpp::vector vect(SIZE)他的效果与静态数组完全相同,但问题在于效率。静态数组是在堆栈上分配内存,而vector模板输在构造函数中使用new操作符分配的,速度比较慢,所以这里有array模板:
scpp_array.h:
#ifndef __SCPP_ARRAY_H__
#define __SCPP_ARRAY_H__
#include "scpp_assert.h"
namespace scpp
{
template <typename T, unsigned N>
class array
{
public:
typedef unsigned size_type;
public:
array(){ }
explicit array(const T& initialValue)
{
for (size_type index = 0; index < N; ++index)
{
data_[index] = initialValue;
}
}
size_type size() const { return N; }
T& operator[](size_type index)
{
SCPP_TEST_ASSERT(index < N,
"Index " << index << " must be less than " << N);
return data_[index];
}
const T& operator[](size_type index) const
{
SCPP_TEST_ASSERT(index < N,
"Index " << index << " must be less than " << N);
return data_[index];
}
T* begin() { return &data_[0]; }
const T* begin() const { return &data_[0]; }
T* end() { return &data_[N]; }
const T* end() const { return &data_[N]; }
private:
T data_[N];
};
}
template <typename T, unsigned N>
inline std::ostream &operator << (std::ostream &os, const scpp::array<T, N>& v)
{
for (unsigned index = 0; index < v.size(); ++index)
{
os << v[index];
if (index + 1 < v.size())
{
os << " ";
}
}
return os;
}
#endif // __SCPP_ARRAY_H__
测试代码(vs2012+win7环境):
#include "stdafx.h"
#include "scpp_assert.h"
#include "iostream"
#include "scpp_vector.h"
#include "scpp_array.h"
#include "algorithm"
#define SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
scpp::array<int, SIZE> str(1);
str[0] = 7;
str[1] = 2;
str[2] = 8;
str[3] = 4;
std::cout << str << std::endl;
std::sort(str.begin(), str.end());
std::cout << str << std::endl;
return 0;
}
这个数组的行为和C的静态数组完全一样。但是,在编译时激活了表示安全检查的SCPP_TEST_ASSERT_ON宏时,他会提供索引边界检查。提供了begin和end方法,所以可以使用algorithm的一些算法
3、多维数组
其实多维数组也就是矩阵,如果矩阵的大小在编译时时已知的,可以很方便地把它实现为数组的数组。因此将注意力集中在当矩阵的大小是在运行时计算产生的这种情况。内部可以用一个vector来存储,返回的时候只需要加上index就行
scpp_matrix.h:
#ifndef __SCCP_MATRIX_H__
#define __SCCP_MATRIX_H__
#include "ostream"
#include "vector"
#include "scpp_assert.h"
namespace scpp
{
template <typename T>
class matrix
{
public:
typedef unsigned size_type;
public:
matrix(size_type numRows, size_type numCols)
:rows_(numRows), cols_(numCols), data_(numCols * numRows)
{
SCPP_TEST_ASSERT(numRows > 0,
"Number of rows in a matrix must be positive");
SCPP_TEST_ASSERT(numCols > 0,
"Number of cols in a matrix must be positive");
}
matrix(size_type numRows, size_type numCols, const T& initValue)
:rows_(numRows), cols_(numCols), data_(numCols * numRows)
{
SCPP_TEST_ASSERT(numRows > 0,
"Number of rows in a matrix must be positive");
SCPP_TEST_ASSERT(numCols > 0,
"Number of cols in a matrix must be positive");
}
size_type numRows() const { return rows_; }
size_type numCols() const { return cols_; }
T& operator() (size_type row, size_type col)
{
return data_[ index(row, col) ];
}
const T& operator() (size_type row, size_type col) const
{
return data_[ index(row, col) ];
}
private:
size_type index(size_type row, size_type col) const
{
SCPP_TEST_ASSERT(row < rows_,
"Row" << row << " must be less than " << rows_);
SCPP_TEST_ASSERT(col < cols_,
"Col" << col << " must be less than " << cols_);
return cols_ * row + col;
}
private:
size_type rows_;
size_type cols_;
vector<T> data_;
};
}
template <typename T>
inline std::ostream &operator << (std::ostream &os, const scpp::matrix<T>& m)
{
for (unsigned rowIndex = 0; rowIndex < m.numRows(); ++rowIndex)
{
for (unsigned colIndex = 0; colIndex < m.numCols(); ++colIndex)
{
os << m(rowIndex, colIndex);
if (colIndex < m.numCols())
{
os << "\t";
}
}
}
return os;
}
#endif
测试代码(vs2012+win7环境):
#include "stdafx.h"
#include "scpp_assert.h"
#include "iostream"
#include "scpp_vector.h"
#include "scpp_array.h"
#include "scpp_matrix.h"
#include "algorithm"
#define SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
scpp::matrix<int> scppMatrix(2, 2);
scppMatrix(0, 0) = 1;
scppMatrix(0, 1) = 2;
scppMatrix(1, 0) = 3;
scppMatrix(1, 1) = 4;
scppMatrix(6, 6) = 4;
std::cout << scppMatrix << std::endl;
return 0;
}