Предотвращение вызова конструктора базового класса при неверном инициализаторе производного класса - PullRequest
0 голосов
/ 26 марта 2020

Рассмотрим следующий пример, где конструкция класса Derived берет указатель на список инициализатора его конструктора. Конечно, я хочу проверить, действителен ли этот указатель, и выдать исключение в противном случае.

Моя попытка не позволяет программе обработать sh, но часть Base все еще создается, прежде чем я смогу выдать исключение.

Есть ли способ предотвратить вызов конструктора класса Base в этом случае?

#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;
}

Ответы [ 3 ]

4 голосов
/ 26 марта 2020

Вы можете вызвать функцию / лямбду перед вызовом конструктора Base:

Derived::Derived(int *val1, int val2) :
    Base([&](){
        if (!val1) {
            throw std::invalid_argument("bad pointer");
        }
        return *val1;
    }()),
    val_d(val2) 
{
}
0 голосов
/ 26 марта 2020

Не понимаю, почему вы этого хотите, но все-таки пытались ли вы потерпеть неудачу в базовом ctor, а не в производном 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;
};
0 голосов
/ 26 марта 2020

Возможно, я неправильно понял ваш вопрос, но рассмотрим этот упрощенный пример:

#include <iostream>

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

Вывод:

destructor

Моя попытка не позволяет программе выполнить sh, но Базовая часть все еще создается, прежде чем я могу выдать исключение.

Это не проблема. Как всегда с исключениями, стек не разматывается, а Base часть Foo должным образом уничтожается. Я не вижу ничего плохого в вашем коде (в смысле серьезно сломан, хотя дизайн спорен). Если построение завершается неудачно и вы выкидываете исключение в теле конструктора, лучше всего вычистить то, что уже построено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...