【问题标题】:std::vector not resizing to accommodate more entries after some number of entries C++std::vector 未调整大小以在一定数量的条目后容纳更多条目 C++
【发布时间】:2020-09-03 01:43:44
【问题描述】:

我有一个自定义向量类,它封装了std::vector。我在 while 循环中使用它逐行读取 CSV 文件并将列存储到名为 columnsVector 中,并对这些值执行一系列操作。一切正常,但是在循环了一些行之后,它会抛出错误:

在抛出 std::out_of_range 的实例后调用终止

我假设我的 Vector 出于某种原因停止调整大小,但它会按照我想要的方式读取每一行,然后再抛出此错误并停止。我使用std::cerr 语句来查看我的几个列值是否被正确读取并使用它,我可以看到它在文件结束之前停止。为什么会这样?

while(getline(datafile, line))
{
    string token;
    Vector<string> columns;
    WindLogType windlog2;
    stringstream ss(line);
    columns.add(string());
    while(getline(ss, token, ','))
    {
        columns.add(token);
    }
    stringstream date(columns[1]);
    string windspeed = columns[11];
    string solar1 = columns[12];
    cerr << solar1 << endl;
    string temperature1 = columns[18];
    cerr << temperature1 << endl; 
}

我的向量类:

#ifndef VECTOR2_H
#define VECTOR2_H
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

template <class T>
class Vector
{
public:
    Vector(){};
    ~Vector();

    void add(const T &obj);
    int vecsize() const{return data.size();}

    T& operator[](const int index);
    const T& operator[](const int index) const;

private:
    vector<T> data;

};

template <class T>
T& Vector<T>::operator[](int index){
    if(index < 0 || index > data.size()){
        throw("Out of bounds");
    }

    return data.at(index);
}

template <class T>
const T& Vector<T>::operator[](int index) const{
    if(index < 0 || index > data.size()){
        throw("Out of bounds");
    }

    return data.at(index);
}

template <class T>
Vector<T>::~Vector(){    
    data.clear();    
}

template <class T>
void Vector<T>::add(const T &obj){    
    data.push_back(obj);    
}

#endif // VECTOR_H

【问题讨论】:

  • 你能告诉我们Vector的相关代码吗?当您不显示此自定义类时,很难帮助您解决自定义类中的错误;)
  • 学习使用调试器或者打印明显太小的向量的大小。
  • @churill 很抱歉。我现在已经编辑了显示我的矢量类的帖子
  • 最好使用调试器来检查向量中的值。不相关,但operator[] 的条件是差一,应该是 ` if(index = data.size()), since data.size()` 已经超出-界限。
  • @thedafferg:运行调试会话并检查这些索引是否存在(1、11、12、18)。访问器正在检查边界,但忽略了index == size() 的情况。应该是index &gt;= 0 &amp;&amp; index &lt; size()。但是,您也不需要检查边界,因为 std::vector::at() 方法已经为您执行此操作,并且它会引发您看到的 std::out_of_range 异常。顺便说一句,您不需要 ctor 和 dtor,因为编译器为您提供了这些,std::vector 有自己的。并且,最好使用std::size_t 作为索引。示例:godbolt.org/z/g9d9xr.

标签: c++ string file csv vector


【解决方案1】:

通常建议避免使用using namespace ...; in a header。如果您要实现已在该命名空间中找到的功能(例如向量),则尤其如此。

您应该考虑抛出一个实际的异常类型,而不是throw("str");,例如std::out_of_range,或者甚至是您自己的异常类型。 throw("str") 有点不寻常,这意味着捕获站点必须使用catch(const char *)。这不是无效的,但也不是常见的做法。

在您的 T&amp; Vector&lt;T&gt;::operator[](int) 函数(和 const-qualified 对应项)中,您正在检查索引是否小于 0(这是正确的),但您正在检查索引是否 大于 em> 内部向量的大小。如果您考虑内部向量为空的情况,那么这意味着根本没有有效索引(因为没有元素),但是,您的验证将允许索引 0 到内部向量,因为它不是大于尺寸。如果内部向量有 1 个元素,那么您的验证允许索引 0 和索引 1,这是不正确的,它应该只允许索引 0。您可以将此检查更改为使用 index &gt;= data.size()。这称为“逐一”错误。

除非您计划提供负索引的实现,否则通常最好使用size_t 或其他无符号整数类型。

最后,不需要在析构函数中显式调用data.clear(),因为向量的析构函数已经这样做了。

【讨论】:

  • 感谢您的建议。在阅读了上面的评论后,它提到我什至不应该在我的运算符重载中添加绑定检查,因为函数处的 std 向量无论如何都会为我做这件事。所以我想知道在运算符重载中我应该在哪里添加我的捕获和尝试?
  • @thedafferg 如果您计划更改底层向量实现(例如,从 std::vector 到另一种没有边界检查的类型),则进行自己的边界检查是有益的。如果你总是在下面使用std::vector,那么.at() 函数会自动为你做边界检查,所以你不需要自己做。您是否在自己的 operator[] 函数中捕捉到这一点在很大程度上是您自己的选择。自己捕获std::out_of_range意味着在这种情况下您可以执行自己的操作,否则由调用者决定做什么
猜你喜欢
  • 2019-10-21
  • 2012-03-11
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
相关资源
最近更新 更多