Возвратите динамическую строку из станд.:: исключение, 'что'

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

Ситуация, что я сталкиваюсь, это было бы действительно удобно если строка what возвраты быть динамичным. Некоторые части кода анализируют XML-файл, например, и добавление положения или номера строки к сообщению об ошибке полезно для меня.

Я пытаюсь следовать инструкциям по Обработке исключений Повышения.

Что я хотел бы знать:

  • what возвраты a const char *, который подразумевает, что любой ловец, вероятно, не собирается освобождать строку. Таким образом, мне нужно некоторое другое место для хранения результата, но где это было бы? (Мне нужна потокобезопасность.)

  • what также включает throw() в его подписи. В то время как я могу предотвратить мой what от броска чего-либо мне кажется, что этот метод действительно не предназначается ни для чего слишком динамического. Если what разве правильное место не, затем где я должен делать это вместо этого?


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

Даже если бы я должен был использовать струну до, то я должен был бы использовать статически размерный буфер или сделать управление памятью, которое может перестать работать также. (Я задаюсь вопросом, является ли это на самом деле единственной вещью, которая может пойти не так, как надо в std::stringконструктор копии. Это означало бы, что я не получу ничего использующего, динамично выделил струны до.)

Там какую-либо другую опцию оставляют?

18
задан Stéphan Kochen 14 April 2010 в 16:23
поделиться

4 ответа

Мои классы исключений обычно не имеют что угодно, кроме конструктора, и просмотрите следующие строки:

class MyEx: public std::runtime_error 
{
public: 
    MyEx(const std::string& msg, int line): 
        std::runtime_error(msg + " on line " + boost::lexical_cast<string>(line)) 
    {} 
}; 

Произвольный пример, но это базовый класс, который обрабатывает управление сообщением what () .

Но если вы хотите, вы также можете назначить базовую часть объекта исключения только после того, как вы собрали сообщение в теле конструктора.

#include <stdexcept>
#include <string>
#include <sstream>

class MyEx: public std::runtime_error
{
public:
    MyEx(const std::string& msg, int line):
        std::runtime_error("")
    {
        std::stringstream ss;
        ss << msg << " on line " << line;
        static_cast<std::runtime_error&>(*this) = std::runtime_error(ss.str());
    }
};

#include <iostream>
int main()
{
    try {
        throw MyEx("Evil code", __LINE__);
    }
    catch (const std::exception& e) {
        std::cout << e.what() << '\n';
    }
}

Однако, что касается рекомендаций по усилению, возможно, вам следует обратить внимание на то, что числовые данные (позиции и строки) лучше всего сделать доступными в виде чисел с помощью других методов. В рекомендациях говорится, что нужно меньше беспокоиться о сообщении what () .

17
ответ дан 30 November 2019 в 08:21
поделиться

Что ж, нет проблем, вы можете просто реализовать конструктор производного класса исключений для форматирования строки, которую вы вернете из what (). Освободите используемый для этого буфер в деструкторе.

3
ответ дан 30 November 2019 в 08:21
поделиться

Я принимаю ответ UncleBens, потому что считаю его технически наиболее правильным и полным ответом на мой первоначальный вопрос.

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

struct Exception : public virtual std::exception
{
  virtual const char* what() const throw()
  {
    try {
      return typeid(this).name();
    }
    catch (const std::exception& e) {
      return "<unknown exception>";
    }
  }

  // Extended description; may throw.
  virtual void describe(std::ostream& out) const = 0;
};

В основном просто заполняю what наиболее значимой вещью, которую я мог найти, не беспокоясь об этом где-либо еще. Думаю, я посмотрю, как все пойдет.

1
ответ дан 30 November 2019 в 08:21
поделиться

Рекомендации Boost, похоже, основаны на двух предположениях: копирование объекта исключения может вызвать другое исключение, а строка what () не является надежной или надежной. орудие труда. Это серьезная проблема, если вы пишете библиотеку, которая будет широко использоваться в различных средах. Если вы лучше знаете, как будет использоваться исключение, вы можете судить, оправданы ли эти опасения или много шума из ничего. Программирование - это серия компромиссов, и компромиссы, которые имеют смысл для разработчиков Boost, могут не относиться к вам.

6
ответ дан 30 November 2019 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: