我正在尝试为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
进行编译。
答案 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
元素的有效索引为0
到backpack.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.");
}
}