我正在尝试为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;
}
}
问题是-=
操作员,旨在在右侧的指示位置擦除元素。当我保持在向量的边界范围内时,这是按预期工作的;但是,如果我指定了删除的界限,我不会得到 exception 。我得到了 seg fault 。我试图通过添加其他打印命令来确定SegFault发生的确切点:
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
编译。
您的错误检查已关闭1。
if (backpack.empty() || backpack.size() < b)
如果std::vector
背包仅包含两个值,则backpack.size()
为2,而backpack
将包含backpack[0]
和backpack[1]
。
不幸的是,如果索引b
被AS 2传递,则此代码仍将尝试访问backpack[2]
,从而导致不确定的行为。
实际上,整个if
语句可以简单地重写为:
if (b >= backpack.size())
throw string("Out of Range");
您的代码中有一个错误。
考虑如果数组不为空,会发生什么,而代码中的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()]
,以提供未定义的行为。
不确定行为的一种可能症状是" segfault"。
避免问题的一种方法是将测试更改为backpack.size() <= b
。
另一种选择是利用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.");
}
}
实时示例