Стандарт не требует специальной оптимизации в случае безымянного объекта исключения. Наоборот, тогда требуется эффект, как если бы временный объект был инициализирован копией. Это копирование может привести к динамическому выделению памяти.
N3290 §15.3 / 16 :
Если объявление-исключение указывает имя, оно объявляет переменную, которая инициализируется копией (8.5) из
объект исключения. Если объявление-исключение обозначает тип объекта, но не указывает имя, временный (12.2) инициализируется копированием (8.5) из объекта исключения. Время жизни переменной или временное
заканчивается при выходе из обработчика, после уничтожения любых автоматических объектов, инициализированных в обработчике.
В приведенном выше параграфе не упоминается отлов по ссылке, и поэтому можно разумно сделать вывод, что он применяется независимо от того, перехвачен ли объект исключения по ссылке; что копия все равно создается.
Однако это противоречит следующему абзацу:
N3290 §15,3 / 17 :
Когда обработчик объявляет непостоянный объект, любые изменения этого объекта не влияют на временный
объект, который был инициализирован выполнением throw-выражения . Когда обработчик объявляет ссылку на
непостоянный объект, любые изменения в ссылочном объекте являются изменениями во временном объекте, инициализированном
когда throw-выражение было выполнено и будет иметь эффект, если этот объект будет переброшен.
Итак, объявленный тип T&
(с T
non- const
) является единственным случаем, когда C ++ 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 выводом является & hellip;
Testing non-const ref:
Default-construction of Error object.
Modified message.
Testing const ref:
Default-construction of Error object.
Modified message
Педантичный формалист мог бы сказать, что оба компилятора не соответствуют друг другу, и ему не удалось создать копию для случая Error const&
. Чисто практичный практикующий может сказать, что, эй, а что еще вы ожидали 1048 *? И мне, я говорю, что формулировка в стандарте здесь очень далека от совершенства, и что, если что-то и следует ожидать, следует внести ясность, чтобы явно разрешить вывод, приведенный выше, так что отлов по ссылке const
является одновременно безопасным и максимально эффективный.
Подводя итог по отношению к вопрос ОП:
Перехват по ссылке не вызовет конструктор копирования, который потенциально может завершить программу.
Стандарт гарантирует это только для ссылок, отличных от const
.
На практике, как показано, это также гарантируется для ссылки на const
, даже когда это влияет на результаты программы.
Приветствия и hth.,