Есть ли лучший способ реализовать механизм try..catch? - PullRequest
1 голос
/ 07 августа 2020

LinkedList.h

#pragma once

class LinkedList {
    int size = 1;
    struct Node {
        int ivar = 0;
        Node* next = nullptr;
    };
    Node* rootNode = new Node();
    Node* createNode(int ivar);
    auto getSize() const { return size; }
public:
    LinkedList() = delete;
    LinkedList(int val) {
        rootNode->ivar = val;
    }
    const bool addNode(int val, int pos);
    const bool delNode(int pos);
    ~LinkedList() = default;
};


LinkedList. cpp

#include <exception>
#include "LinkedList.h"

LinkedList::Node* LinkedList::createNode(int ivar) {
    try {
        Node* newNode = new Node();
        newNode->ivar = ivar;
        return newNode;
    }
    catch (const std::exception&) {
        return nullptr;
    }
}

const bool LinkedList::addNode(int val, int pos = -1) {
    pos = (pos >= size) || (pos < 0) ? getSize() - 1 : pos;
    Node* newNode = createNode(val);
    if (newNode == nullptr) {
        return false;
    }
    Node* temp_ptr = rootNode;
    for (int i = 0; i < pos; i++) {
        temp_ptr = temp_ptr->next;
    }
    temp_ptr->next = newNode;
    size++;
    return true;
}

const bool LinkedList::delNode(int pos) {
    pos = (pos >= size) || (pos < 0) ? getSize() - 1 : pos;
    try {
        auto temp_ptr = rootNode;
        if (pos == 0) {
            rootNode = rootNode->next;
        }
        else {
            for (int i = 0; i < pos - 1; i++) {
                temp_ptr = temp_ptr->next;
            }
        }
        temp_ptr->next = temp_ptr->next->next;
    }
    catch (const std::exception&) {
        return false;
    }
    size--;
    return true;
}

Это код для назначения связанного списка. Есть ли лучший способ реализовать механизм try-catch?

Ответы [ 2 ]

2 голосов
/ 07 августа 2020

Какие исключения C ++ не являются

Исключения не являются альтернативным способом реализации if / else. У исключений совершенно другая и гораздо более сложная семантика, и они созданы исключительно для обработки ошибок. Фактически, это такой топи c, что до 1994 года никто толком не знал, как написать правильный безопасный код исключений.

Что делать с исключениями

  • Распечатать их / log them et c et c
  • Перебросить их заново, чтобы тот, кто вызовет ваш метод, мог поймать исключение и узнать, что пошло не так.

Что произойдет, если вы не 't поймать исключение

  • std::terminate вызывается, и ваша программа завершается

Когда использовать исключения

  • Используйте исключения, когда вы можете не обрабатывать ошибку локально внутри функции. Пример:

Когда использовать try / catch

Используйте try / catch, когда вы знаете , что какая-то функция или фрагмент кода могут вызвать исключение.

попробуйте {// код здесь может выбросить this_func_can_throw_in_some_cases (); } catch (exception & e) {...}

struct A{
   A() {
    //some error happened here. Now you can't tell anyone about the error.
    //You can't return error code or true/false from the constructor.
    //Use exceptions!
    throw myexception("Something bad happened");
   }
};

//
void somefunc()
{
    try {
       A a; //constructor of A can throw
    } catch (const myexception& e) {
        std::cout << e.what() << std::endl;  //
        throw; //rethrow the exception.
    }
}

Ваш код

В вашем коде в методе createNode:

LinkedList::Node* LinkedList::createNode(int ivar) {
    try {
        Node* newNode = new Node();
        newNode->ivar = ivar;
        return newNode;
    }
    catch (const std::bad_alloc &ba) {
        std::cout << "Failed to allocate: " << ba.what() << std::endl;
        throw;
    }
}

int main()
{
  try {
     list.createNode(...)
  } catch (const std::bad_alloc& ba)
  {
     //failed...
     //no rethrowing, we are already in main and we can't rethrow stuff from here.
  }
}

Это бессмысленно:

    try {
        auto temp_ptr = rootNode;
        if (pos == 0) {
            rootNode = rootNode->next;
        }
        else {
            for (int i = 0; i < pos - 1; i++) {
                temp_ptr = temp_ptr->next;
            }
        }
        temp_ptr->next = temp_ptr->next->next;
    }
    catch (const std::exception&) {
        return false;
    }

Здесь нет необходимости в try / catch, потому что ничто в блоке try не может выбросить. Если ничего не может throw, значит catch просто сидит и ничего не делает. Вы можете безопасно удалить это.

Я предлагаю вам прочитать главу Исключения и обработка ошибок в ISO cpp FAQ для подробного введения в этот топ c. В частности, узнайте о

  • Узнайте о гарантиях безопасности исключений (слабые / сильные)
  • Где не использовать исключения (например, в деструкторах)
2 голосов
/ 07 августа 2020

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

  • Если есть конкретное исключение c, из которого вы точно знаете, как восстановить (что-то вроде GUI не удалось, вернуться к текстовому пользовательскому интерфейсу), сделайте свой план резервного копирования.
  • Во всех остальных случаях зарегистрируйте его (в файл журнала, поток журнала и т. Д. c) повторно выбросите исключение.

В вашем конкретном случае c вам лучше выключено, не перехватывая исключение, поскольку вы ничего с ним не делаете.

Также вы можете увидеть этот доклад под названием "Declarative Control Flow" , в котором описываются способы замены try...catch для улучшения структуры кода.

...