如何直接从构造函数结束 C++ 代码?

Posted

技术标签:

【中文标题】如何直接从构造函数结束 C++ 代码?【英文标题】:How to end C++ code directly from a constructor? 【发布时间】:2017-10-01 17:40:48 【问题描述】:

如果满足某个条件,我希望我的 C++ 代码停止运行并进行适当的对象清理;在类的构造函数中。

class A 
public:
    int somevar;
    void fun() 
        // something
    
;

class B 
public:
    B() 
        int possibility;
        // some work
        if (possibility == 1) 
            // I want to end the program here
            kill code;
        
    
;

int main() 
    A a;
    B b;
    return 0;
    

我如何在此时终止我的代码以进行适当的清理。众所周知,std::exit 不执行任何类型的堆栈展开,并且堆栈上的任何活动对象都不会调用其各自的析构函数来执行清理。所以std::exit 不是一个好主意。

【问题讨论】:

如果构造函数失败抛出异常。 调用 std::exit 之前的 std::atexit 怎么样? @SeverinPappadeux - 这不会展开堆栈。并且必须进行实际上允许std::atexit 清理所有内容的管理,这违背了使用 C++ 的目的。我们有 RAII,我们应该使用它。 值得注意的是,std::exit() 将为所有全局对象调用析构函数(是的,它不会展开堆栈)。如果您想“杀死”该程序,您可以改用_exit() 【参考方案1】:

当构造函数失败时,你应该抛出一个异常,像这样:

B() 
  if(somethingBadHappened)
  
    throw myException();
  

一定要在main() 和所有线程入口函数中捕获异常。

在Throwing exceptions from constructors 中了解更多信息。在How can I handle a destructor that fails 中了解堆栈展开。

【讨论】:

... 并确保在main 和所有线程入口函数中捕获异常。【参考方案2】:

仅从构造函数执行是不可能的。如果你抛出异常,那么应用程序需要在入口点设置适当的异常处理代码,因为如果你只是抛出了一个不会被处理的异常,那么编译器就可以跳过堆栈展开和清理。

【讨论】:

【参考方案3】:

如果你不想使用 use 异常,你可以在类 B 中有一个返回返回码的 init 方法:

class B 
public:
    B(/*parameters that will be used by init*/) : ...
    int init(); // actually initialize instance and return non 0 upon failure

【讨论】:

构造函数的目的就是你所说的 "init" 方法,只是构造函数远没有那么邪恶。例如,他应该如何“init” member-data 比如std::vector?还有他应该怎么写B的析构函数呢? 我知道这一点,但遗憾的是,在 C++ 中没有好的方法可以毫无例外地解决这个问题。另请参阅第一个链接问题,如果您不想引发异常,则可以使用 init 方法。 是什么让你认为 OP 不想使用异常?问题实际上是关于终止程序执行适当的清理,而不是关于一般的构造失败处理。对于错误代码,开发人员需要设置返回代码检查链直到入口点。 很多开发者不想或者不允许抛出异常,这有很多原因。我并不是说 OP 不应该抛出异常,我是说如果是这种情况,这个答案就是建议的解决方案的替代方案。

以上是关于如何直接从构造函数结束 C++ 代码?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 如何在构造函数中启动一个线程,从命名管道读取数据?

C++ 虚继承派生类构造函数的写法

c++ 编译器会绕过拷贝构造函数

C++如何使用派生类构造函数销毁基类中的对象

C++ - 构造函数与析构函数的使用

这段代码安全吗,可以从构造函数 C++ 生成线程吗?