std :: vector segfaulting而不是抛出异常

时间:2016-11-22 03:02:16

标签: c++ vector exception-handling segmentation-fault

我正在尝试为std::vector创建容器类,以便更多地了解模板,重载运算符以及管理异常。

目前,我只是定义基本操作。我有一个下面列出的模板类;我已将+=[]运算符重载为push_back vector T,并分别直接访问向量的元素。这可以按预期工作。

+=运算符执行它应该执行的操作,并且尝试在超出范围的元素上使用[]运算符将按预期抛出异常。

这是目前的原型类和实现:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <class T>
class Inventory
{
    public:
        void operator += (const T& b)   { backpack.push_back(b); }

        T operator [] (const unsigned& b)
        {
            if (backpack.empty() || backpack.size() < b)
                throw string("Out of Range");
            return backpack[b];
        }

        void operator -= (const unsigned& b)
        {
            if (backpack.empty() || backpack.size() < b)
                throw string("No such element exists.");
            backpack.erase(backpack.begin() + b);
        }

    private:
        vector<int> backpack;
};

int main()
{
    Inventory<int> pack;
    pack += 2;
    pack += 4;
    try
    {
        cout << "It was " << pack[0] << endl;
        cout << "It was " << pack[1] << endl;
        pack -= 0;
        cout << "It is now " << pack[0] << endl;
        //pack -= 1; // Segfaults?
    }
    catch (string e)
    {
        cout << "Error: " << e << endl;
    }
}

问题在于-=运算符,用于擦除右侧指示位置的元素。当我停留在向量的边界内时,这可以按预期工作;但是,如果我指定要删除的越界数字,我不会得到异常;我得到了一个 seg-fault 。我试图通过添加其他打印命令来确定段错误发生的确切点:

void operator -= (const unsigned& b)
{
    cout << "In Overload!\n";
    if (backpack.empty() || backpack.size() < b)
    {
        cout << "Exception!\n";
        throw string("No such element exists.");
    }
    backpack.erase(backpack.begin() + b);
}

“例外!”永远不会到达。程序在达到该点之前就会出现故障,即使我应该评估未定义的行为。我相信我错过了理解这个过程如何运作的关键组成部分。我有没有办法写这个,所以它可以抛出而不是错误?

在Linux x64架构上使用g++ -std=c++17 -Wall -Wextra -pedantic进行编译。

3 个答案:

答案 0 :(得分:1)

您的错误检查已关闭1.

if (backpack.empty() || backpack.size() < b)

如果std::vector背包只包含两个值,backpack.size()将为2,backpack将包含backpack[0]backpack[1]

不幸的是,如果索引b被传入2,则此代码仍将尝试访问backpack[2],从而导致未定义的行为。

事实上,整个if语句可以简单地重写为:

if (b >= backpack.size())
    throw string("Out of Range");

答案 1 :(得分:1)

您的代码中有“off by one”错误。

考虑如果数组不为空且代码中为b == backpack.size()会发生什么。

 if (backpack.empty() || backpack.size() < b)
            throw string("Out of Range");
 return backpack[b];

在这种情况下,backpack元素的有效索引为0backpack.size() - 1

如果b == backpack.size(),代码不会抛出异常,并且会尝试返回backpack[backpack.size()],这会给出未定义的行为。

未定义行为的一个可能症状是“段错误”。

避免此问题的一种方法是将测试更改为backpack.size() <= b

答案 2 :(得分:0)

另一个选择是利用std::vector::at(),它会在越界索引上抛出std::out_of_range异常:

    T operator [] (const unsigned& b)
    {
        try 
        {
           return backpack.at(b);
        }
        catch (std::out_of_range& e)
        {
            throw string("Out of Range");
        }
    }

    void operator -= (const unsigned& b)
    {
        try
        {
            backpack.at(b);
            backpack.erase(backpack.begin() + b);
        }
        catch(std::out_of_range& e)
        {
           throw std::string("No such element exists.");
        }
    }

Live Example