一旦创建对象,例外处理

发布于 2025-01-28 10:11:49 字数 1094 浏览 4 评论 0原文

我对应该在哪里进行例外以及在哪里捕捉它感到有些困惑。现在,一旦有人创建了一本具有无效页面的书,我就会立即扔一个无效的_argument。

在我的主要功能中,我正在用无效的页面创建一本书,并且我正在抓住这个例外并写出消息。这是您应该如何做的吗?因为现在我只捕获一本书的一个实例。如果我尝试使用无效的页面在尝试捕获块之外创建另一本书,我将无法捕捉它。这真的有必要吗?这是我应该处理异常的方式吗?

#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

 class Book
  {
  public:
    string title {};
    string author {};
    int pages {};
    int readers {};

    Book(string const& t, string const& a, int const p)
        : title{t}, author{a}, pages{p}, readers{0}
    {
      if (pages <= 0)
        throw invalid_argument ("Invalid page!");
    }

    void print() const
    {
    cout << "Title: " << title << "\nAuthor: " << author
         << "\nPages: " << pages << "\nReaders: " << readers << endl;
    }
    
  };

int main()
{
  try
  {
    Book book_1("Harry Potter", "JK Rowling", 0);
  }
  catch(const exception& e)
  {
    cerr << "Exception: " << e.what() << endl;
  }
  
  //book_1.print(); 

  return 0;
}

I am a bit confused on where I should throw an exception and where I should catch it. Right now I am throwing an invalid_argument as soon as someone creates a book with an invalid page.

In my main function I am then creating a book with an invalid page and I am catching that exception and writing out the message. Is this how you are supposed to do it? Because right now I am only catching one single instance of a book. If I tried to create another book outside the try catch block with an invalid page I woudnt be able to catch it. Is this really necessary? Is this how I'm supposed to handle exceptions?

#include <iostream>
#include <string>
#include <stdexcept>

using namespace std;

 class Book
  {
  public:
    string title {};
    string author {};
    int pages {};
    int readers {};

    Book(string const& t, string const& a, int const p)
        : title{t}, author{a}, pages{p}, readers{0}
    {
      if (pages <= 0)
        throw invalid_argument ("Invalid page!");
    }

    void print() const
    {
    cout << "Title: " << title << "\nAuthor: " << author
         << "\nPages: " << pages << "\nReaders: " << readers << endl;
    }
    
  };

int main()
{
  try
  {
    Book book_1("Harry Potter", "JK Rowling", 0);
  }
  catch(const exception& e)
  {
    cerr << "Exception: " << e.what() << endl;
  }
  
  //book_1.print(); 

  return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你列表最软的妹 2025-02-04 10:11:49

是的,如果您调用可能会引发异常的函数,在某个时候,您将需要处理它。这样做的方法是捕获例外。

真的有必要吗?

很好。如果在您的情况下确保不会使用无效的论点创建对象,则无需捕获永远不会提出的例外。
例外处理是仅需要当您不知道时(您没有保证),例如,当从用户输入给出页面参数时, file 或任何未知/不可预测/不受代码库控制的内容。


话虽如此,在您的情况下,您可以做得更好,只需替换:

int pages;

unsigned int pages;

,然后再也无法给出一个无效的数字。这意味着您可以完全删除处理您的代码的异常。

上面的提案没有考虑到0也被认为也无效。

Yes, if you call a function that may throw an exception, at some point, you will need to handle it. The way to do it is to catch the exception.

Is it really necessary?

Well it depends. If in your case you ensure that you won't create your objects with invalid arguments, you don't need to catch an exception that'll never be raised.
Exception handling is only required when you don't know (you have no guarantee), for example when the page parameter is given from a user input, a file or anything that is unknown/not predictable/not controlled by the code base.


That being said, in your case you can do even better, just replace:

int pages;

with:

unsigned int pages;

And then it would not be possible to give an invalid number anymore. Which means you can completely remove the exception handling off your code.

The above proposal didn't take into account that 0 is considered invalid as well.

笨笨の傻瓜 2025-02-04 10:11:49

您应该捕获并处理对程序有意义的例外。

首先,您的程序始终引发异常独立于输入,因为0是硬编码的。对于例外,这似乎不是用例。这似乎是一个逻辑错误,因此应将其视为需要修复的错误。尝试创建保证无效的书籍应该有意义?

但是,让我们假设用户输入给出了页数。然后,下一个问题是您无法打印未创建的书。因此,book_1.print();必须是尝试块的一部分。

假设您有第二本书book_2,也是从用户输入创建的。您需要问自己,然后如果创建第一本书失败,则程序逻辑继续创建和使用第二本书是否有意义。

如果未能创建第一本书意味着继续第二本书是没有意义的,那么只需将所有内容放入一个try block,例如:

try
{
  Book book_1(/*...*/);
  book_1.print();

  Book book_2(/*...*/);
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

当书创作失败时,该程序将继续在catch处理程序中执行,然后在其之后执行,然后跳过书籍的其余部分创建和打印。但是,如果book_1没有进行施工,则将在book_2“检查”之前打印出来。

也许您希望

try
{
  Book book_1(/*...*/);
  Book book_2(/*...*/);

  book_1.print();
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

这样做,如果这两本书的创作失败,则该程序将不会打印任何书。

如果如果第一本书的创建失败,则程序是否确实有意义,请使用两个尝试/catch语句单独处理这些错误:

try
{
  Book book_1(/*...*/);
  book_1.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

try
{
  Book book_2(/*...*/);
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

您可能需要考虑使用功能或阵列和循环以使其减少多余,例如,如果目标是重复进行用户输入,创建书然后打印,那么简单的循环将有所帮助:

while(true)
{
  try
  {
    /* take user input here */
    if(/* some exit condition */)
    {
        break;
    }
    Book book(/* arguments from user input */);
    book.print();
  }
  catch(const exception& e)
  {
    cerr << "Exception: " << e.what() << endl;
  }
}

此循环将运行直到出口条件直到出口条件满足。如果抛出任何标准异常(来自图书创建或输入操作),则将打印出异常消息,并重新循环。

(附加说明:在上面的所有示例中,所有的异常。这意味着invalid_argument本书创建的异常,例如.print()或输入处理的任何例外。例如,作为输入操作的例外情况,该程序可能没有办法继续循环。 /code>)对于throw 的构造函数,只捕获您可以专门处理无效的书籍。

You should catch and handle the exception where it makes sense for the program.

First of all, your program always throws the exception independent of input, because the 0 is hard-coded. This doesn't seem to be a use case for an exception. This seems to be a logic error and so it should be considered a bug that needs fixing. Why should it make sense to try to create a guaranteed invalid book?

But let's suppose the number of pages is given by user input. Then the next issue would be that you can't print a book that failed to be created. So book_1.print(); must be part of the try block.

Let's suppose you have a second book book_2, also created from input from the user. You need to ask yourself then whether it makes sense for the program logic to continue creating and using the second book if creating the first one failed.

If failing to create the first book means that there is no point in continuing with the second book, then just put everything in one try block, e.g.:

try
{
  Book book_1(/*...*/);
  book_1.print();

  Book book_2(/*...*/);
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

When either of the book creations fail, the program will continue executing in the catch handler and then after it, skipping over the rest of the book creations and printing. But if book_1 didn't throw on construction, then it will be printed before book_2 is "checked".

Maybe you would want

try
{
  Book book_1(/*...*/);
  Book book_2(/*...*/);

  book_1.print();
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

With this the program will not print any book if creation of either book fails.

If it does make sense for the program to continue execution if creation of the first book failed, then use two try/catch statements to handle the errors individually:

try
{
  Book book_1(/*...*/);
  book_1.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

try
{
  Book book_2(/*...*/);
  book_2.print();
}
catch(const exception& e)
{
  cerr << "Exception: " << e.what() << endl;
}

You might want to consider using a function or arrays and loops to make this less redundant, for example if the goal is to just repeatedly take user input, create a book and then print it, a simple loop will be helpful:

while(true)
{
  try
  {
    /* take user input here */
    if(/* some exit condition */)
    {
        break;
    }
    Book book(/* arguments from user input */);
    book.print();
  }
  catch(const exception& e)
  {
    cerr << "Exception: " << e.what() << endl;
  }
}

This loop will run until the exit condition is satisfied. If any standard exception (from book creation or the input operation) is thrown, the exception message will be printed and the loop continues anew.

(As an additional note: In all of the examples above all exceptions inherited from std::exception thrown in the try blocks will be caught. This means not only the invalid_argument exception from the book creation, but e.g. any exception thrown by .print() or the input handling. You may not want to handle these the same way as the invalid book creation. For example an exception from input operations could mean that there is no way for the program to continue the loop. Therefore it makes sense to use a custom class (maybe inherited from std::invalid_argument) for the throw in Book's constructor and catch only that. This way you can handle the invalid book creation specifically.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文