C++ List类setEntry函数异常处理问题及实现疑问
问题分析与解决方案
核心错误点
- 异常检查顺序颠倒:你的
setEntry函数先执行赋值操作list[pos] = item,再判断pos是否合法。这会导致两个问题:一是触发非法内存访问(比如空列表时pos=2,数组下标越界),二是即使抛出异常,之前的非法操作已经引发未定义行为。 - 数组下标偏移错误:类的接口规定pos从1开始(范围1~getLength()),但C++数组下标从0开始,直接使用
list[pos]会修改错误的位置,甚至触发越界。 - 未捕获的异常:main函数开头调用
songs.setEntry(2, "Bohemian Rhaspody")时,列表是空的(getLength()返回0),pos=2超出合法范围触发异常,但这个调用没有被try-catch块包裹,导致程序直接终止。
修正后的setEntry函数
必须遵循先检查合法性,再执行操作的原则,同时修正数组下标:
#include <stdexcept> // 必须包含此头文件以使用std::invalid_argument template<class ItemType> void List<ItemType>::setEntry(int pos, const ItemType& item) { // 第一步:检查位置合法性,不合法直接抛出异常 if (pos < 1 || pos > getLength()) { throw std::invalid_argument("ERROR: setEntry() using invalid position"); } // 第二步:合法则修改对应位置(数组下标=pos-1) list[pos - 1] = item; }
修正main函数以处理异常
如果要测试异常功能,必须将setEntry的调用放到try-catch块中,同时避免在空列表时调用setEntry:
#include <iostream> #include <string> #include <stdexcept> using namespace std; // 实现getTrack函数示例 int getTrack() { int num; cout << "Enter track number: "; cin >> num; return num; } // 插入你的List类定义... int main() { List<string> songs; char goAgain = 'y'; int trackNumber; string trackName; // 先插入元素,让列表有合法的位置范围 songs.insert(1, "Bohemian Rhaspody"); songs.insert(2, "The Highway Song"); songs.insert(3, "In the Loop"); songs.insert(4, "Lovesong"); songs.insert(5, "Blow The Whistle"); songs.remove(1); // 测试setEntry的异常处理 try { songs.setEntry(2, "Updated Highway Song"); // 合法位置,正常执行 cout << "成功修改第2首歌\n"; songs.setEntry(5, "Invalid Track"); // 非法位置,触发异常 } catch (const std::invalid_argument& e) { cout << "捕获到异常:" << e.what() << endl; } cout << "Welcome! There are " << songs.getLength() << " tracks.\n"; while (goAgain != 'n') { trackNumber = getTrack(); try { trackName = songs.getEntry(trackNumber); } catch (const std::invalid_argument& arg) { cout << arg.what() << endl; trackName = "No Track"; } cout << "Your track name is " << trackName << endl; cout << "Go again? (y/n) "; cin >> goAgain; } cout << "you're ready to rock!\n"; return 0; }
关键注意事项
- 必须包含
<stdexcept>头文件,否则std::invalid_argument无法被编译器识别。 - 捕获异常时建议使用const引用(
const std::invalid_argument& e),避免不必要的异常对象拷贝。 - 永远先验证输入合法性,再执行核心操作,防止非法内存访问引发的未定义行为。
内容的提问来源于stack exchange,提问作者evanparial
相关产品推荐
相关产品推荐

