If a C programmer asks "do you want to see something cool?", run away.
--John Van Enk

Thursday, January 10, 2008

А возможно и не const...

Прочитав недавно в блоге Алёны С++ статью Возможно, самый важный const, губоко задумался нельзя ли все-таки как нибудь обойти запрет на следующее

string&s = string("abc");
int&i = 1;

И совершенно неожиданно вспомнил, что когда-то давным-давно на далеком-далеком форуме (чет меня опять не туда понесло ;-)) прочитал о том, как тимлид учил зеленых программеров: "тыкаем в любое место throw 1; если программа летит - бьем дубиной по голове"

Это я к тому что при генерации исключения происходит его копирование, поэтому обработчик имеет копию исходного исключения. Хотя на реализацию не накладывается ограничений и исключение может быть скопировано несколько раз до того, как будет перехвачено. Т.е. исключение, которое не может быть скопировано - не может быть и перехвачено.

try {
throw 1;
}
catch(int&i){
//можем менять i
}
catch(...){}


Проверяем

try {
try {
throw 1;
}
catch(int&i){
cout<<"int& "<<i<<endl;
i=2;
throw;
}
catch(...){}
}
catch(int&i){
cout<<"int& "<<i<<endl;
}
catch(...){}


Факт повторной генерации исключения отмечается отсутствием операнда у throw. Причем повторно сгенерированное исключение является исходным исключением (копией или нет - думаю зависит от реализации, по крайней мере в Стандарте ничего не нашел по этому поводу. Может плохо искал? Пните меня в комментах, если найдете). Хотя по идее оно должно копироваться, так как это все же генерация, хоть и повторная. Однако в реализации gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21), которой я на данный момент пользуюсь, в момент повторной генерации эксепшн не копируется.


#include <iostream>
#include <cstdlib>

//класс исключения
class ex {
public:
ex(const ex&){cout<<"Copy ctor"<<endl;};
ex(){cout<<"ctor"<<endl;};
~ex(){cout<<"dtor"<<endl;}
};
//
int main(int argc, char *argv[])
{
try {
try {
throw ex();
}
catch(ex&){cout<<"Rethrow"<<endl;throw;}
catch(...){throw;}
}
catch(ex&){}
catch(...){}
return EXIT_SUCCESS;
}

Причем, что интересно, на отсутствие copy constructor ругается, если его private или explicit сделать, а в процессе распространения исключения и при генерации его не использует.

Update
В результате пинков открыл таки 15.1 пункт Стандарта и почитал его. И как правильно заметили в комментариях, время жизни ссылки все равно ограничено обработчиком и не превышает время жизни временной переменной, а время жизни временной переменной, в свою очередь, определяется другим механизмом, а не наличием ссылок на нее.

Update2
15.1.6
A throw-expression with no operand rethrows the exception beeing handled. The exception is reactivated with existing temporary; no new temporary exception object is created.

Так что во время повторной генерации исключения копирования не происходит.