Как добавить проверку ошибок в функцию-член класса? - PullRequest
1 голос
/ 06 мая 2020

Учитывая класс и одну из его функций-членов, например:

// constructor
class Stitcher::Stitcher(const std::vector<cv::Mat> imgs)
{
    calibrate(imgs);
}

// one of its member functions that gets called upon construction
void Stitcher::calibrate(const std::vector<cv::Mat> imgs)
{ 
    // Do some stuff here
}

При построении этого объекта Stitcher он запускает функцию calibrate при построении. Однако calibrate иногда дает сбой, и мне нужен способ справиться с такими сбоями. Я думал вернуть логическое значение, но не знал, как это сделать, потому что мне все еще нужен доступ к объекту Stitcher для других функций-членов. В основном я создаю его вот так: Stitcher stitcher(images);, который работает нормально, пока не дает сбоев. Тогда я могу использовать stitcher.stitch(), stitcher.otherFunction(), и т.д. c. Любые предложения для этого C ++ newb ie о том, как обрабатывать ошибки внутри функции-члена класса?

Ответы [ 3 ]

2 голосов
/ 06 мая 2020

Существует идиома RAII (получение ресурсов - инициализация), которая настоятельно рекомендуется в C ++. Одним из аспектов RAII является идея о том, что не должно существовать плохо сконструированных или неинициализированных объектов. Из вашего вопроса я делаю вывод, что вы пытаетесь инициализировать объект, но иногда это невозможно. Это приложение RAII.

В функциях конструктора C ++ не возвращаются коды ошибок, поэтому есть еще один метод обработки ошибок: исключения. Вкратце исключение, созданное конструктором, не позволяет вам оставить еще не построенный объект в частично построенном состоянии.

class Stitcher {
public:
    Stitcher(const std::vector<cv::Mat> &imgs) {
        calibrate(imgs);
        // If the calibrate method fails, the object is not being constructed.
        // The next line will not be executed on a non-calibrated object:
        doSmthWithCalibratedImgs(imgs);
    }
private:
    void calibrate(const std::vector<cv::Mat> &imgs) { 
        // Do some stuff here
        // if cannot calibrate:
        throw exception("Cannot calibrate");
    }
};

Таким образом, следующей задачей будет обработка возможных исключений из кода, который создает объекты Stitcher.

Обратите внимание, что я изменил сигнатуру методов для передачи вектора по константной ссылке: я думаю, это то, что вам нужно. Еще одна вещь, которая может вам понадобиться, - это сохранить вектор imgs внутри объекта как член данных, но это зависит от задачи и зависит от вас.

1 голос
/ 06 мая 2020

Первый вопрос, на который вы должны ответить (относительно вашей бизнес-логики c): должен ли сбой calibrate(imgs) также означать сбой при построении объекта типа Stitcher.

1. Возможность: calibrate(imgs) не удается, но объект построен. Вам понадобятся некоторые методы-члены (что-то вроде isCalibrated (..), recalibrate () ... et c.), Чтобы иметь возможность запрашивать объект, если калибровка прошла успешно, и, возможно, попытаться выполнить повторную калибровку, если предварительные условия выполнены в другой раз, et c.

2. Возможность: Stitcher постусловие конструктора - калибровка прошла успешно. В этом случае вы не можете мириться с ошибкой, поэтому вам нужно сгенерировать исключение внутри конструктора. В связи с этим вам, возможно, придется решить, какую гарантию безопасности исключений вы хотели бы предложить. Здесь у вас есть 3 варианта:

i) сильная гарантия безопасности исключений (лучший выбор, если возможно)

ii) basi c гарантия безопасности исключений (второй лучший выбор)

iii) гарантия безопасности без исключений (худший вариант)

В принципе, выполнение работы в конструкторе не является хорошей практикой. Вы можете рассмотреть конструкцию Stitcher, настроив необходимые элементы данных в конструкторе и соблюдая все необходимые предварительные условия, а затем предоставив некоторые методы-члены, например, например. Calibrate () - с возвратом false при сбое, TryCalibrate () - генерирует исключение, et c., Поэтому клиенты Stitcher лучше контролируют обработку сбоев.

1 голос
/ 06 мая 2020

Что вы могли бы сделать, так это создать исключение, чтобы указать на проблему, которая возникает во время выполнения вашей программы. В стандартной библиотеке есть несколько классов исключений , которые вы можете использовать для создания исключения, все из которых являются производными от std:exception. Например, std::out_of_range.

Чтобы создать стандартное исключение, вы создаете строку, описывающую исключение, и используете ее для инициализации объекта исключения:

std::string s("my exception")
...
throw std::out_of_range(s);

Вы также можете написать:

throw std::out_of_range("out of from somewhere");

с использованием неявного преобразования из char* в std::string.


Другая возможность - определить свой собственный специальный класс исключения, производный прямо или косвенно от std::exception. Однако вы должны предоставить переопределенную виртуальную функцию what() в своем классе:
class MyException: public std::exception
{
    public:
        MyException(...){
        }

    virtual const char* what() const throw() {
         return "C++ Exception";
    }
};

Другой способ предоставить функцию what() - получить класс исключения из одного из классов, которые имеют строку конструктор для аргумента what():

class MyException: public std::out_of_range
{
    public:
        MyException(const std::string &what): std::out_of_range(what) {}
};

Таким образом, вы можете использовать разные классы для разных типов исключений.


Теперь вы можете выбросить исключение в Stitcher::calibrate(), но для его перехвата нужен блок try ... catch. Примерно так:
try
{
    Stitcher stitcher;
    // this will be executed if no exception is thrown
}
catch (const std::exception &e)
{
    std::cout << e.what();
}
...