C++ 从构造函数的初始化列表中捕获异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/160147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:21:18  来源:igfitidea点击:

Catching exceptions from a constructor's initializer list

c++exception

提问by Head Geek

Here's a curious one. I have a class A. It has an item of class B, which I want to initialize in the constructor of A using an initializer list, like so:

这是一个好奇的。我有一个 A 类。它有一个 B 类项目,我想使用初始化列表在 A 的构造函数中对其进行初始化,如下所示:

class A {
    public:
    A(const B& b): mB(b) { };

    private:
    B mB;
};

Is there a way to catch exceptions that might be thrown by mB's copy-constructor while still using the initializer list method? Or would I have to initialize mB within the constructor's braces in order to have a try/catch?

有没有办法在仍然使用初始化列表方法的同时捕获可能由 mB 的复制构造函数抛出的异常?或者我是否必须在构造函数的大括号内初始化 mB 才能进行 try/catch?

回答by Adam Wright

Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

阅读http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/

Edit: After more digging, these are called "Function try blocks".

编辑:经过更多挖掘,这些被称为“功能尝试块”。

I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)

我承认在我去看之前我也不知道这一点。你每天都会学到一些东西!我不知道这是否是对我现在很少使用 C++、我缺乏 C++ 知识,或者语言中经常出现的拜占庭特性的控诉。嗯 - 我仍然喜欢它:)

To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:

为了确保人们不必跳转到另一个站点,构造函数的函数 try 块的语法结果是:

C::C()
try : init1(), ..., initn()
{
  // Constructor
}
catch(...)
{
  // Handle exception
}

回答by Michael Burr

It's not particularly pretty:

它不是特别漂亮:

A::A(const B& b) try : mB(b) 
{ 
    // constructor stuff
}
catch (/* exception type */) 
{
    // handle the exception
}

回答by Mikhail Semenov

I know it has been awhile since this discussion started. But that try-and-catch construct mentioned by Adam is part of the C++ standard and is supported by Microsoft VC++ and GNU C++. Here is the program that works. By the way the the catch generates automatically another exception to signal about the constructor failure.

我知道这个讨论已经有一段时间了。但是 Adam 提到的 try-and-catch 结构是 C++ 标准的一部分,并且得到 Microsoft VC++ 和 GNU C++ 的支持。这是有效的程序。顺便说一下,catch 会自动生成另一个异常以发出有关构造函数失败的信号。

#include <iostream>
#include <exception>
#include <string>

using namespace std;

class my_exception: public exception
{
  string message;
public:
  my_exception(const char* message1)
  {
    message = message1;
  }

  virtual const char* what() const throw()
  {
     cout << message << endl;
     return message.c_str();
  }

  virtual ~my_exception() throw() {};
};

class E
{
public:
    E(const char* message) { throw my_exception(message);}
};

class A
{
    E p;
public:
    A()
  try :p("E failure")
    {
            cout << "A constructor" << endl;
    }
  catch (const exception& ex)
    {
        cout << "Inside A. Constructor failure: " << ex.what() << endl;
    }
};


int main()
{
    try
    {
        A z;
    }
    catch (const exception& ex)
    {
        cout << "In main. Constructor failure: " << ex.what() << endl;
    }
    return 0;
}

回答by IceFire

You could work with lazy initialization, though, that is hold a unique_ptr to Reader in MyClass and create it with new. That way, you do not even need the flag has_reader but you can just see if your unique_ptr is initial or not.

不过,您可以使用延迟初始化,即在 MyClass 中为 Reader 保存一个 unique_ptr 并使用 new 创建它。这样,您甚至不需要标志 has_reader 但您可以查看您的 unique_ptr 是否为初始值。

#include <iostream>
#include <memory>
using namespace std;

class MyOtherClass
{
public:
    MyOtherClass()
    {
        throw std::runtime_error("not working");
    }
};

class MyClass
{
public:
    typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;

    MyClass()
    {
        try
        {
            other = std::make_unique<MyOtherClass>();
        }
        catch(...)
        {
            cout << "initialization failed." << endl;
        }

        cout << "other is initialized: " << (other ? "yes" : "no");
    }

private:
    std::unique_ptr<MyOtherClass> other;
};

int main()
{
    MyClass c;

    return 0;
}

Of course, there are also solutions without using exceptions at all but I assumed that this is a prerequisite in your setting.

当然,也有完全不使用异常的解决方案,但我认为这是您设置的先决条件。

回答by Mark Bessey

I don't see how you'd do that with initializer-list syntax, but I'm also a bit sceptical that you'll be able to do anything useful by catching the exception in your constructor. It depends on the design of the classes, obviously, but in what case are you going to fail to create "mB", and still have a useful "A" object?

我不知道你会如何使用初始化列表语法来做到这一点,但我也有点怀疑你是否能够通过在构造函数中捕获异常来做任何有用的事情。显然,这取决于类的设计,但是在什么情况下您将无法创建“mB”,并且仍然拥有一个有用的“A”对象?

You might as well let the exception percolate up, and handle it wherever the constructor for A is being called.

您不妨让异常渗透,并在调用 A 的构造函数的任何地方处理它。