使用 stoi 函数进行异常处理

Lev*_*aya 2 c++ string exception

我在 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 << "\n\nPlease enter a number (end-of-file to terminate): ";
   }
Run Code Online (Sandbox Code Playgroud)

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

Arm*_*gny 5

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

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

也许,但我不知道,您只想捕获std::stoi引发的标准异常。这些都是:

写起来很容易

        // 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";
        }
Run Code Online (Sandbox Code Playgroud)

但也许您想学习如何编写自己的异常。针对您的具体要求。但请注意,您的规范,例如“超过 10 位数字”和“无字母”可能并不完全是您想要的。对于一台机器,其中 int 是 32bit 位,可以转换的最大数字是: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;
}
Run Code Online (Sandbox Code Playgroud)

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

请参见:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但也许,您真正想要的是一个函数,它封装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 converted\n";
    }
    return 0;
}

Run Code Online (Sandbox Code Playgroud)