происходит от std :: exception - PullRequest
       1

происходит от std :: exception

7 голосов
/ 01 февраля 2011

Я хочу получить из std :: exception, чтобы добавить конкретную информацию в мои файлы журналов, но я не могу понять, как получить доступ к .what () из std :: exception.

Более того, я знаю, что создавать строку в моем обработчике исключений небезопасно, но я не эксперт по этой теме, так что есть более безопасные альтернативы?

struct Exception : public std::exception, private boost::noncopyable
{
    public:
        Exception(std::string msg)
            : message(msg)
        {}
        ~Exception()
        {}

        virtual const char* what() const throw 
        {
            std::string what = message + // and now what? base.what()
            LOG(what); // write to log file
            return what.c_str();
        }

    private:
        std::string message;
};

EDIT: я действительно задал вопрос неправильно. Я скорее заинтересован в безопасности, я просто подумал, что было бы неплохо иметь больше данных для регистрации. я был неправ.

Теперь я не настолько параноидален из-за того, что bad_alloc выдается строкой сообщения на случай, если раньше был bad_alloc, я бы предпочел аккуратное сообщение. при этом я переписал некоторые вещи:

struct Exception : public std::exception
{
    public:
        Exception(std::string msg)
            : message(msg)
        {}
        ~Exception()
        {}

        virtual const char* what() const throw 
        {
            LOG(what); // write to log file
            return what.c_str();
        }

    private:
        std::string message;
};

Есть ли еще какие-то серьезные опасения по поводу этого кода сейчас? LOG () выдает std :: exception, в случае, если что-то идет не так, потому что я не хотел бесконечный цикл вызова журнала производным классом исключений, и этот класс снова вызывает журнал, что снова вызовет такое же исключение Будет ли это работать так, как я хочу, или будет исключение при регистрации в моем вызове производного класса terminate () или вызовет дамп ядра?

Ответы [ 4 ]

9 голосов
/ 01 февраля 2011

РЕДАКТИРОВАТЬ : С момента написания этого ответа я наткнулся на раздел Обработка ошибок и исключений в документе Boost.Я бы рекомендовал этот документ поверх этого ответа.


Прежде всего, сделать ваше исключение не подлежащим копированию - плохая идея.Когда вы пишете что-то вроде

// could be any exception, doesn't matter.
throw Exception(...);

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

Тогда все остальное зависит от того, насколько вы параноидальны с угловыми случаями.

Часть выделения памятив основном исключение в предложении исключения (т.е. конструктор).Если это выделение памяти происходит неудачно (т. Е. Выбрасывается std::bad_alloc), есть две возможности, в зависимости от того, как вы пишете оператор throw:

  1. std::string создается до throw оператор, std::bad_alloc заменяет исключение, которое, как вы думали, возникнет, проблема вроде плохо сообщена.
  2. std::string создается встроенным в вызове конструктора.Если в стандарте это считается «во время обработки исключений», то будет вызван std::unexpected()/std::terminate(), и вы в основном получите дамп ядра.

В любом случае кажется, что вы не получите желаемогоЭффект сообщения об ошибке.

Я всегда рекомендую создать какое-то временное состояние, которое не выделяет память в конструкторе, и дождаться вызова std::what(), чтобы создать строку, сообщающую об ошибке, ноэто все еще может привести к делу № 1.Вы можете прибегнуть к некоторому определенному во время компиляции размеру буфера, чтобы убедиться, что этого не произойдет.

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

4 голосов
/ 01 февраля 2011

Я не буду вдаваться в многочисленные проблемы с вашим кодом, потому что это огромная банка червей. Но вот как вы вызываете метод базового класса:

std::exception::what()
3 голосов
/ 01 февраля 2011

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

Обратите внимание, что стандарт не предоставляет функциональности в std :: exception, чтобы обеспечить строковое значение для начала. Те реализации, которые фактически предоставляют полезную информацию от вызова std :: exception :: what (), добавляют дополнительную, нестандартную функциональность к классу. Например, MSVC имеет конструктор exception(char const* const&). Это не в стандарте, и вы, вероятно, не хотите зависеть от этого.

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

Если вы настаиваете на непосредственном вызове этой функции, тогда вам, черт побери, лучше проверить NULL, потому что это то, что вы, вероятно, получите.

0 голосов
/ 01 февраля 2011

для второй части. У меня есть несколько сотен kloc, которые работают на> 100 платформах, которые имеют производный класс std :: exception с членами std :: string. Никогда не было проблем с этим

class myex: public std::exception
{
public:
    std::string m_msg;
    std::string m_className;
    int m_rc;
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...