C++索引越界的解决方法

作者:Welcom to LyAsano’s blog! 时间:2023-07-21 21:53:17 

避免"索引越界"错误的规则如下(针对C++):

  • 不要使用静态或动态分配的数组,改用array或vector模板

  • 不要使用带方括号的new和delete操作符,让vector模板为多个元素分配内存

  • 使用scpp::vector代替std::vector,使用scpp::array代替静态数组,并打开安全检查(自动在使用下标访问提供了索引边界检查)

C++中创建类型T的对象的数组方式如下:


#define N 10
T static_arr[N]; //数组长度在编译时已知

int n=20;
T* dynamic_arr=new T[n]; //数组长度在运行时计算

std::vector<T> vector_arr; //数组长度在运行时进行修改

1. 动态数组

采用的办法是继承std::vector<T>,并重载<< 、[]运算符,提供一个能够捕捉越界访问错误的实现。

实现代码和测试如下:


//scpp_vector.h
#ifndef  _SCPP_VECTOR_
#define  _SCPP_VECTOR_

#include <vector>
#include "scpp_assert.h"

namespace scpp {

//wrapper around std::vector,在[]提供了临时的安全检查:重载[] <<运算符
   template<typename T>
   class vector : public std::vector<T> {
       public:
            typedef unsigned size_type;

//常用的构造函数 commonly use cons
            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) {

}

//Note : we don't provide a copy-cons and assignment operator  ?

//使用scpp::vector提供更安全的下标访问实现,它可以捕捉越界访问错误
            T& operator[] (size_type index) {
                SCPP_ASSERT( index < std::vector<T>::size() ,
                    "Index " << index << " must be less than " << std::vector<T>::size());
                return std::vector<T>::operator[](index);
            }

//? difference
            const T& operator[] (size_type index) const {
                SCPP_ASSERT( index < std::vector<T>::size() ,
                    "Index " << index << " must be less than " << std::vector<T>::size());
                return std::vector<T>::operator[](index);
            }

//允许此函数访问这个类的私有数据
            //friend std::ostream& operator<< (std::ostream& os,const ) ?
           };
} //namespace

template<typename T>
inline  std::ostream& operator<< (std::ostream& os,const scpp::vector<T>& v) {
   for(unsigned i=0 ;i<v.size();i++) {
           os << v[i];
           if( i+1 < v.size()) os << " ";
   }
   return os;
}

#endif

//test_vector.cpp
#include "scpp_vector.h"
#include <iostream>

using namespace std;
int main() {
   //usage-创建一个具有指定数量的vector:scpp::vector<int> v(n); 把n个vector元素都初始化为一个值:scpp::vector<int> v(n,val)
   //方法3:scpp::vector<int> v; v.reserve(n),表示开始的vector是空的,对应的size()为0,
   //并且开始添加元素时,在长度达到n之前,不会出现导致速度降低的容量增长现象
   scpp::vector<int> vec;
   for(int i=0;i< 3;i++){
       vec.push_back(4*i);
   }
   cout << "The vector is : "<< vec <<endl;

for(int i=0;i <= vec.size();i++) {
       cout << "Value of vector at index " << i << " is " << vec[i] << endl;
   }
   return 0;
}

我们直接使用scpp::vector而尽量不与std::vector交叉使用。

2.静态数组

静态数组是在栈上分配内存,而vector模板是在构造函数中用new操作符分配内存的,速度相对慢些,为保证运行时效率,建议使用array模板(同样也是栈内存),实现代码和测试如下:


//scpp_array.h
#ifndef _SCPP_ARRAY_H_  
#define _SCPP_ARRAY_H_

#include "scpp_assert.h"

namespace scpp {

//wrapper around std::vector,在[]提供了临时的安全检查
//fixed-size array
template<typename T,unsigned int N>
class array {
   public:
        typedef unsigned int size_type;

//常用的构造函数 commonly use cons
       array() {}
       explicit array(const T& val) {
           for(unsigned int i=0;i < N;i++) {
                    m_data[i]=val;
                }
       }

size_type size() const {
           return N;
       } //must use const if we use the size()

//Note : we don't provide a copy-cons and assignment operator  ?

T& operator[] (size_type index) {
            SCPP_ASSERT( index < N,
                    "Index " << index << " must be less than " << N);
            return m_data[index];
        }

//? difference
       const T& operator[] (size_type index) const {
            SCPP_ASSERT( index < N ,
                    "Index " << index << " must be less than " << N);
            return m_data[index];
       }

//模拟迭代器的begin和end方法
        //访问方法accessors
       T* begin() {
           return &m_data[0];
       }

const T* begin() const {
           return &m_data[0];
       }

//返回越过数组尾部的迭代器
       T* end() {
            return &m_data[N];
       }

const T* end() const {
            return &m_data[N];
       }
   private:
       T m_data[N];
   };
} //namespace scpp

template<typename T,unsigned int N>
inline  std::ostream& operator<< (std::ostream& os,const scpp::array<T,N>& v) {
   for(unsigned int i=0 ;i< N;i++) {
           os << v[i];
           if( i+1 < v.size()) os << " ";
   }
   return os;
}
#endif

//test_array.cpp
#include "scpp_array.h"
#include <iostream>
#include <algorithm> //sort algorithm
using namespace std;
int main() {
   //use vector/array class instead of static array or dynamic array
   scpp::array<int,5u > arr(0);
   arr[0]=7;
   arr[1]=2;
   arr[2]=3;
   arr[3]=9;
   arr[4]=0;

cout << "Array before sort : " << arr << endl;
   sort(arr.begin(),arr.end());
   cout << "Array after sort : "<< arr << endl;

arr[5]=8;
   return 0;
}

来源:https://www.cnblogs.com/AsanoLy/p/15093442.html

标签:C++,索引,越界
0
投稿

猜你喜欢

  • c#基于WinForm的Socket实现简单的聊天室 IM

    2021-11-27 04:47:57
  • C#遍历得到checkboxlist选中值和设置选中项的代码

    2022-10-25 20:52:22
  • 分析Android 11.0Settings源码之主界面加载

    2021-05-25 23:15:02
  • Android使用Retrofit2.0技术仿微信发说说

    2021-05-24 03:09:18
  • springboot+jersey+tomcat实现跨域方式上传文件到服务器的方式

    2023-08-16 10:26:45
  • java递归算法实例分析

    2022-02-09 07:59:17
  • SpringBoot中多环境配置和@Profile注解示例详解

    2023-11-29 05:39:04
  • springboot 使用自定义的aspect的示例代码

    2023-08-06 08:55:14
  • SpringBoot整合Echarts实现用户人数和性别展示功能(详细步骤)

    2023-02-22 00:31:59
  • maven下载jar包改用阿里云maven库的方法

    2023-02-13 07:41:58
  • Android双向选择控件DoubleSeekBar使用详解

    2022-02-13 10:05:29
  • C#实现图形区域组合操作的方法

    2023-05-01 19:08:21
  • SpringBoot整合Shiro框架,实现用户权限管理

    2021-10-27 00:03:02
  • C# goto语句的具体使用

    2021-07-22 22:26:22
  • C#调用百度翻译实现翻译HALCON的示例

    2022-06-08 23:33:50
  • c#多进程通讯的实现示例

    2022-09-06 02:43:23
  • android横竖屏切换时候Activity的生命周期

    2021-12-10 16:02:36
  • 【java 多线程】守护线程与非守护线程的详解

    2023-11-29 01:35:29
  • Java同步函数代码详解

    2022-10-13 23:22:03
  • C#中实现网段扫描的代码

    2022-05-09 03:54:33
  • asp之家 软件编程 m.aspxhome.com