Выбрасывание, отлов, определение исключений stl :: string.c_str ()

Скажем, я написал некоторую функцию myFunc, которая может генерировать исключения const char *:

void myFunc()
{
    int returnCode = whatever();
    if (!returnCode)
    {
        std::string msg;
        msg.append("whatever function failed");
        std::cerr << msg << std::endl; // print warning message
        throw msg.c_str(); // throw warning message as exception
    }
}

А потом использую вот так:

void myProgram()
{
    try
    {
        myFunc();
    }
    catch(const char* str)
    {
        // is 'str' string memory valid here?
    }
}

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


person Mike Clark    schedule 04.05.2011    source источник
comment
трудно ответить на ваш вопрос, когда вы меняете его в ответ на ответы.   -  person Robᵩ    schedule 04.05.2011
comment
@ Роб, теперь я это вижу. Я буду избегать этого в будущем. Спасибо за ответ.   -  person Mike Clark    schedule 04.05.2011


Ответы (4)


msg.str() возвращает временный std::string. Поскольку временные объекты удаляются в конце оператора ;, содержимое символьной строки, возвращаемой c_str(), становится неопределенным, когда оператор throw ... ; завершает работу, покидая область действия с помощью механизма исключения.

(Время существования временного const char*, очевидно, расширено, чтобы достичь обработчика catch, но это не помогает, поскольку базовый буфер отсутствует).


Бросок std::string (т.е. throw msg.str();) будет работать, время жизни временного будет увеличено, как задумано.

person Alexander Gessler    schedule 04.05.2011
comment
К сожалению, мой пример программы был недостаточно сфокусирован, потому что он использовал ostringstream в дополнение к string. Я изменил его, чтобы использовать только string, поэтому мы можем игнорировать последствия использования ostringstream. Спасибо! - person Mike Clark; 04.05.2011
comment
Время жизни временного не будет увеличиваться, но поскольку throwing копирует то, что выбрасывается, это не проблема. (Когда бросается char const*, конечно, копируется только указатель, а не то, на что он указывает.) - person James Kanze; 04.05.2011
comment
@Mike Clark Совет по сути тот же - предпочитаю бросать std::string. Вы можете безопасно использовать const char*, только если он указывает на статически выделенную область памяти, которая все еще действительна на сайте-перехватчике. throw "whatever function failed" поэтому было бы хорошо. - person Alexander Gessler; 04.05.2011
comment
Что, если создание временного объекта std::string вызвало исключение? См. Мой ответ (и предлагаемое решение). - person Unsigned; 15.07.2012

Действительно, вызов c_str() действует на временный (string) объект, и указатель станет недействительным, когда вы его поймаете.

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

Вы не можете использовать say runtime_error или создать свой собственный тип исключения?

person Mark B    schedule 04.05.2011
comment
К сожалению, мой пример программы был недостаточно сфокусирован, потому что он использовал ostringstream в дополнение к string. Я изменил его, чтобы использовать только string, поэтому мы можем игнорировать последствия использования ostringstream. Мы действительно переходим к использованию реальных классов исключений и разработаем шаблон использования runtime_error в случае проблем с распределением. Однако мне все еще интересно это. Спасибо! - person Mike Clark; 04.05.2011

Обратите внимание: если бы вы сказали:

throw "error";

все будет в порядке, потому что время жизни строкового литерала - это время жизни программы. Но все равно не делайте этого!

person Community    schedule 04.05.2011

Александр Гесслер не упомянул в своем ответе возможность исключение создается самим std::string во время создания временного строкового объекта.

std::exception гарантированно не вызовет исключения во время построения, std::string не имеет такой гарантии.

Альтернативный подход (для классов) - объявить частный объект std::string в вашем классе. Соберите сообщение об ошибке до throw, а затем выбросьте c_str(). Это вызовет исключение const char*, при этом сообщение об ошибке будет действительным до тех пор, пока из этого класса не будет выброшено следующее исключение (которое, вероятно, снова изменит строку ошибки).

Здесь можно найти простой пример: http://ideone.com/d9HhX

person Unsigned    schedule 14.07.2012