书有点模糊。它不是“运行时错误”,而是在运行时出现的未定义行为。这意味着任何事情都可能发生。但是错误完全出在您身上,而不是程序执行上,事实上,甚至谈论具有未定义行为的程序的执行也是不可能和不明智的。
C++ 中没有任何东西可以保护您免受编程错误的影响,这与 Java 完全不同。
正如@sftrabbit 所说,std::vector
它有一个替代接口,.at()
它总是给出一个正确的程序(尽管它可能会抛出异常),因此它是一个可以推理的程序。
让我用一个例子来重复这一点,因为我相信这是 C++ 的一个重要的基本方面。假设我们正在从用户那里读取一个整数:
int read_int()
{
std::cout << "Please enter a number: ";
int n;
return (std::cin >> n) ? n : 18;
}
现在考虑以下三个程序:
危险的一点:这个程序的正确性取决于用户输入!它不一定是不正确的,但它是不安全的(到了我称之为损坏的地步)。
int main()
{
int n = read_int();
int k = read_int();
std::vector<int> v(n);
return v[k];
}
无条件正确:无论用户输入什么,我们都知道这个程序的行为。
int main() try
{
int n = read_int();
int k = read_int();
std::vector<int> v(n);
return v.at(k);
}
catch (...)
{
return 0;
}
理智的人:上面的版本.at()
很尴尬。最好检查并提供反馈。因为我们执行动态检查,所以实际上保证了未检查的向量访问是没问题的。
int main()
{
int n = read_int();
if (n <= 0) { std::cout << "Bad container size!\n"; return 0; }
int k = read_int();
if (k < 0 || k >= n) { std::cout << "Bad index!\n"; return 0; }
std::vector<int> v(n);
return v[k];
}
(我们忽略了向量构造可能引发自身异常的可能性。)
寓意是,C++ 中的许多操作都是不安全的,并且只能在条件下正确,但程序员希望您提前进行必要的检查。语言不会为你做这件事,所以你不需要为此付费,但你必须记住去做。这个想法是无论如何您都需要处理错误情况,因此与其在库或语言级别执行昂贵的、非特定的操作,责任留给了程序员,他们可以更好地集成检查进入无论如何都需要编写的代码。
如果我想变得有趣,我会将这种方法与 Python 进行对比,Python 允许您编写非常短且正确的程序,而根本不需要任何用户编写的错误处理。不利的一面是,任何尝试使用与程序员的意图略有不同的此类程序的任何尝试都会给您留下非特定的、难以阅读的异常和堆栈跟踪,并且几乎没有关于您应该做得更好的指导。您不必编写任何错误处理程序,而且通常最终不会编写任何错误处理程序。(我无法将 C++ 与 Java 完全对比,因为虽然 Java 通常是安全的,但我还没有看到一个简短的Java 程序。)</rantmode>