使用 stoi 功能进行异常处理



我在 c++ 中处理异常时遇到了一点问题。我需要将数字转换为字符串,如果此字符串包含字母或超过 10 个字符,我需要给出错误。这是异常处理部分;

while ( cin >> input )
{
try
{ 
convert = castInput( input );
cout << "The number entered was: " << convert;
} 
catch ( NonNumber &excp )
{
cout << "INVALID INPUT: " << excp.what();
} 
catch ( Overflow &excp )
{
cout << "INVALID INPUT: " << excp.what();
} 
cout << "nnPlease enter a number (end-of-file to terminate): ";
}

我使用 stoi 函数将字符串转换为 int,但我认为我需要打开 2 个类。我不知道为什么以及如何拥有什么功能。

我个人认为正则表达式并不过分。使用正则表达式检查用户输入不会对性能产生任何负面影响。

但我认为您对异常处理更感兴趣。您需要阅读一本好的C++书的许多页才能理解异常处理及其用例。

也许,但我不知道,你只是想捕捉std::stoi抛出的标准异常。这些是:

  • 标准::invalid_argument
  • 标准::out_of_range

那很容易写

// Standard exceptions for stoi
catch (const std::invalid_argument & e) {
std::cout << e.what() << "n";
}
catch (const std::out_of_range & e) {
std::cout << e.what() << "n";
}

但也许你想学习如何编写自己的异常。满足您的特定要求。但请注意,您的规格,例如"超过 10 位数字"和"无字母"可能不是您想要的。对于 int 为 32 位位的机器,可以转换的最大数字为:2147483647。任何更大的数字仍然只有 10 个字符,都会抛出一个std::out_of_range。另一方面,像 123X 这样的数字将被std::stoi转换为 123。所以,也许你的要求不是那么清楚。

无论如何,为了向您展示如何使用自己的异常,我创建了 2 个自定义异常类。为了让生活变得轻松,我从std::exception(推荐(中衍生出这些。

请参阅以下示例:

#include <iostream>
#include <string>
#include <algorithm>
#include <exception>
#include <cctype>
#include <vector>
#include <sstream>
class StoiException : public std::exception
{
public:
StoiException(const std::string& msg) : message(msg) {}
virtual const char* what() const noexcept override { return message.c_str(); }
protected:
void setMessage(const std::string& msg) { message = msg; }
protected:
std::string message{};
};
class NoNumber : StoiException
{
public:
NoNumber(const std::string& msg) : StoiException(msg) { setMessage(std::string("My Exception -> NoNumber: ") + msg); }
virtual const char* what() const noexcept override { return message.c_str(); }
};
class Overflow : StoiException
{
public:
Overflow(const std::string& msg) : StoiException(msg) { setMessage(std::string("My Exception -> Overflow: ") + msg); }
virtual const char* what() const noexcept override { return message.c_str(); }
};
int castInput(std::string& input) {
int result{};
// Check, if there is any letter in the input string
if (std::any_of(input.begin(), input.end(), isalpha)) {
// If so, than throw
throw NoNumber(input);
}
// Check, if string has more than 10 characters
if (input.length() > 10) {
// If so, than throw
throw Overflow(input);
}
result = std::stoi(input);
return result;
}
std::istringstream testCin{ R"(123
567
2147483647
2147483648
123X
12345678901
xyzxyzxyzxyzxyz
)" };

int main() {
std::string input{};
// Read all input
while (testCin >> input) {
try {
// Convert
int convert = castInput(input);
// This will only be shown , if there is no exception
std::cout << "nConverted Number is: " << convert << "n";
}
// Catch all exceptions
catch (const NoNumber & e) {
std::cout << e.what() << "n";
}
catch (const Overflow & e) {
std::cout << e.what() << "n";
}
// Standard exceptions for stoi
catch (const std::invalid_argument & e) {
std::cout << e.what() << "n";
}
catch (const std::out_of_range & e) {
std::cout << e.what() << "n";
}
}
return 0;
}

当然,您也可以在自定义转换器函数中处理std::stoi的异常。然后,只有您的 owwn 异常可见。

请看:

#include <iostream>
#include <string>
#include <algorithm>
#include <exception>
#include <cctype>
#include <vector>
#include <sstream>
class StoiException : public std::exception
{
public:
StoiException(const std::string& msg) : message(msg) {}
virtual const char* what() const noexcept override { return message.c_str(); }
protected:
void setMessage(const std::string& msg) { message = msg; }
protected:
std::string message{};
};
class NoNumber : StoiException
{
public:
NoNumber(const std::string& msg) : StoiException(msg) { setMessage(std::string("My Exception -> NoNumber: ") + msg); }
virtual const char* what() const noexcept override { return message.c_str(); }
};
class Overflow : StoiException
{
public:
Overflow(const std::string& msg) : StoiException(msg) { setMessage(std::string("My Exception -> Overflow: ") + msg); }
virtual const char* what() const noexcept override { return message.c_str(); }
};
int castInput(std::string& input) {
int result{};
// Check, if there is any letter in the input string
if (std::any_of(input.begin(), input.end(), isalpha)) {
// If so, than throw
throw NoNumber(input);
}
// Check, if string has more than 10 characters
if (input.length() > 10) {
// If so, than throw
throw Overflow(input);
}
try {
result = std::stoi(input);
}
// Standard exceptions for stoi
catch (const std::invalid_argument & e) {
throw NoNumber(input);
}
catch (const std::out_of_range & e) {
throw Overflow(input);
}
return result;
}
std::istringstream testCin{ R"(123
567
2147483647
2147483648
123X
12345678901
xyzxyzxyzxyzxyz
)" };

int main() {
std::string input{};
// Read all input
while (testCin >> input) {
try {
// Convert
int convert = castInput(input);
// This will only be shown , if there is no exception
std::cout << "nConverted Number is: " << convert << "n";
}
// Catch all exceptions
catch (const NoNumber & e) {
std::cout << e.what() << "n";
}
catch (const Overflow & e) {
std::cout << e.what() << "n";
}
}
return 0;
}

但也许,你真正想要的是一个函数,它封装std::stoi并有一个额外的返回值来显示它是否有效。

请注意:最后一个解决方案也会将"123X"转换为 123。这是与以前版本的区别。

#include <iostream>
#include <string>
#include <algorithm>
#include <exception>
#include <cctype>
#include <vector>
#include <sstream>

std::pair<bool, int> castInput(std::string& input) {
bool ok{ false };
int result{};
try {
result = std::stoi(input);
ok = true;
}
// Catch stoi errors
catch (const std::invalid_argument & e) {}
catch (const std::out_of_range & e) {}
return {ok, result};
}
std::istringstream testCin{ R"(123
567
2147483647
2147483648
123X
12345678901
xyzxyzxyzxyzxyz
)" };

int main() {
std::string input{};
// Read all input
while (testCin >> input) {
const auto [ok, convert] = castInput(input);
if (ok)
std::cout << "Converted value: " << convert << "n";
else
std::cout << "String '" << input << "' could not be convertedn";
}
return 0;
}

为什么不使用正则表达式?您只需创建一个正则表达式,检查是否有字母或超过 10 个字符,具体取决于您处理转换或抛出自定义异常的返回。

这可能是您正在寻找的正则表达式:^[0-9]{1,10}$

std::regex reg("^[0-9]{1,10}$");
if (std::regex_match(string, reg))
// Do what you want (process convert)

这是正则表达式 cpp 参考:这里

编辑:如前所述,正则表达式对此矫枉过正,因此您可以简单地在函数内部进行一些基本检查castInput并在字符串中找到字符时抛出NonNumber,或者如果 string.len> 10Overflow则抛出。

最新更新