Бросать, ловить, ограничивать исключения stl :: string.c_str () - PullRequest
1 голос
/ 04 мая 2011

Допустим, я написал некоторую функцию 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?
    }
}

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

Ответы [ 4 ]

1 голос
/ 14 июля 2012

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

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

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

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

1 голос
/ 04 мая 2011

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

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

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

1 голос
/ 04 мая 2011

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

throw "error";

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

1 голос
/ 04 мая 2011

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

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


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

...