Стандарт не требует специальной оптимизации в случае безымянного объекта исключения. Напротив, тогда требуется эффект, как если бы временный объект был инициализирован копированием. Это копирование может привести к динамическому выделению памяти.
N3290 §15.3/16:
Если в объявлении-исключения указано имя, оно объявляет переменную, которая инициализируется копированием (8.5) из объекта-исключения. Если объявление-объявления-исключения указывает тип объекта, но не указывает имя, временное (12.2) инициализируется копированием (8.5) из объекта-исключения. Время жизни переменной или временного объекта заканчивается, когда обработчик завершает работу после уничтожения любых автоматических объектов, инициализированных в обработчике.
В приведенном выше абзаце не упоминается перехват по ссылке, поэтому можно разумно заключить, что он применяется независимо от того, перехватывается ли объект исключения по ссылке; что копия строится в любом случае.
Однако этому противоречит следующий абзац:
N3290 §15.3/17:
Когда обработчик объявляет непостоянный объект, любые изменения этого объекта не повлияют на временный объект, который был инициализирован выполнением выражения throw-expression. эм>. Когда обработчик объявляет ссылку на непостоянный объект, любые изменения в объекте, на который делается ссылка, являются изменениями во временном объекте, инициализированном при выполнении throw-expression, и будут действовать, если этот объект будет создан повторно.
Таким образом, объявленный тип T&
(с T
не-const
) — это единственный случай, когда С++ 11 требует прямой ссылки на брошенный объект вместо копирования. То же самое и в C++03, за исключением того, что в C++03 есть некоторые дополнительные формулировки об оптимизации «как если бы». Таким образом, для формального предпочтение должно быть для
catch( T& name )
и
catch( T& )
Однако я всегда ловил такие исключения, как catch( T const& )
. С практической точки зрения можно предположить, что компилятор оптимизирует это до прямой ссылки на выбрасываемый объект, хотя можно придумать случаи, когда наблюдаемый программный эффект будет тогда нестандартным. Например <evil grin>
#include <stdio.h>
#include <stdexcept>
struct Error
: std::runtime_error
{
public:
static Error* pThrown;
char const* pMessage_;
Error()
: std::runtime_error( "Base class message" )
, pMessage_( "Original message." )
{
printf( "Default-construction of Error object.\n" );
pThrown = this;
}
Error( Error const& other )
: std::runtime_error( other )
, pMessage_( other.pMessage_ )
{
printf( "Copy-construction of Error obejct.\n" );
}
char const* what() const throw() { return pMessage_; }
};
Error* Error::pThrown = 0;
int main()
{
printf( "Testing non-const ref:\n" );
try
{
throw Error();
}
catch( Error& x )
{
Error::pThrown->pMessage_ = "Modified message.";
printf( "%s\n", x.what() );
}
printf( "\n" );
printf( "Testing const ref:\n" );
try
{
throw Error();
}
catch( Error const& x )
{
Error::pThrown->pMessage_ = "Modified message";
printf( "%s\n", x.what() );
}
}
Как с MinGW g++ 4.4.1, так и с Visual C++ 10.0 вывод
Testing non-const ref:
Default-construction of Error object.
Modified message.
Testing const ref:
Default-construction of Error object.
Modified message
Педантичный формалист мог бы сказать, что оба компилятора не соответствуют требованиям и не могут создать копию для случая Error const&
. Чисто практический практик может сказать, что эй, что еще вы ожидали? И я говорю, что формулировка в стандарте здесь очень далека от совершенства, и что, во всяком случае, следует ожидать уточнения, чтобы явно разрешить вывод выше, так что также отлов по ссылке на const
и безопасен, и максимально эффективен.
Подводя итоги вопрос ОП:
Перехват по ссылке не вызовет конструктор копирования, который потенциально может завершить программу.
Стандарт гарантирует это только для ссылки на не-const
.
На практике, как показано, это также гарантируется для ссылки на const
, даже если это повлияет на результаты программы.
Ура и чт.,
person
Cheers and hth. - Alf
schedule
13.09.2011
my_exception&
является стандартной практикой, я обнаружил, что в большинстве случаев исключение не изменяется, и поэтому было бы лучше перехватитьmy_exception const&
. Обратите внимание, чтоwhat
равноconst
. - person Matthieu M.   schedule 13.09.2011