防止在无效的 Derived class 初始值设定项上调用 Base class 构造函数

Prevent Base class constructor being called on invalid Derived class initializer

考虑以下示例,其中 Derived class 的构造在其构造函数的初始化列表中采用指针。当然我想检查这个指针是否有效,否则抛出异常。

我的尝试阻止了程序崩溃,但 Base 部分在我抛出异常之前仍在构造中。

有什么方法可以防止在这种情况下调用 Base class 构造函数?

#include <stdlib.h>
#include <iostream>

class Base
{
public:
    Base(int val) : val_b(val)
    {
        std::cout << "Base::CTOR" << std::endl;
    }
    ~Base() { }

    int val_b;
};

class Derived : public Base
{
public:
    Derived(int *, int);
    ~Derived() { }

    int val_d;

    void print(void)
    {
        std::cout << "Base:\t" << val_b << std::endl;
        std::cout << "Derived:" << val_d << std::endl;
    }

};

Derived::Derived(int *val1, int val2) : Base(val1 ? *val1 : -1), val_d(val2) 
{
    if (!val1)
    {
        throw std::invalid_argument("bad pointer");
    }
}

int main()
{
    int *a = NULL;  
    int b = 43;

    try 
    {
        Derived *d = new Derived(a, b);
        d->print();
    }
    catch (std::exception &e)
    {
        std::cout << "Exception: " << e.what() << std::endl;
    }

    return 0;
}

也许我误解了你的问题,但考虑这个简化的例子:

#include <iostream>

struct Base {
    ~Base() { std::cout <<"destructor";}
};
struct Foo : Base {
    Foo() : Base() {
        throw 1;
    }
};
int main()
{
    try {
        Foo f;
    } catch(...){}
}

输出为:

destructor

My attempt prevents the program to crash but Base part is still constructed before I can throw the exception.

这不是问题。与往常一样,堆栈被展开并且 FooBase 部分被正确销毁。我看不出你的代码有什么问题(在严重破坏的意义上,尽管设计值得商榷)。如果构造失败并且您在构造函数的主体中抛出异常,那么清理已经构造的内容是您能做的最好的事情。

我不明白你为什么想要它,但无论如何你试过在 Base ctor 而不是 Derived ctor 中失败吗?

class Base
{
public:
    Base(int *val)
    {
        if (!val)
        {
            throw std::invalid_argument("bad pointer");
        } 
        val_b = val;
        std::cout << "Base::CTOR" << std::endl;
    }
    ~Base() { }

    int val_b;
};

您可以在调用 Base 构造函数之前调用 function/lambda:

Derived::Derived(int *val1, int val2) :
    Base([&](){
        if (!val1) {
            throw std::invalid_argument("bad pointer");
        }
        return *val1;
    }()),
    val_d(val2) 
{
}