В одном из модулей создается глобальный объект этого класса.
A g_a;
Можно ли бросить исключение следующим образом:
throw g_a;
Такой код компилируется и даже работает, но:
1. На подсознательном уровне чувствую, что так делать неправильно.
2. Ниразу не видел такого ни в одной книге или в открытом коде.
Развейте, пожалуйста, мои сомнения, или помогите их аргументировать.
Меняется ли ситуация если глобальный объект константный.
Здравствуйте, ShubinEV, Вы писали:
SEV>Развейте, пожалуйста, мои сомнения, или помогите их аргументировать. SEV>Меняется ли ситуация если глобальный объект константный.
Так делать можно, если у класса есть доступный конструктор копии.
Но, возможно, это сделает не то, что ты хочешь. Полетит всё равно копия глобального объекта, а не он сам.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
... SEV>Такой код компилируется и даже работает, но: SEV>1. На подсознательном уровне чувствую, что так делать неправильно. SEV>2. Ниразу не видел такого ни в одной книге или в открытом коде. SEV>Развейте, пожалуйста, мои сомнения, или помогите их аргументировать.
Будет брошена копия глобального объекта, а не ссылка на него, как ты, вероятно, думал.
15.1.3
A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing
any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from “array of T”
or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively. [ Note: the temporary object
created for a throw-expression that is a string literal is never of type char* or wchar_t*; that is, the special conversions
for string literals from the types “array of const char” and “array of const wchar_t” to the types “pointer to char”
and “pointer to wchar_t”, respectively (4.2), are never applied to a throw-expression. —end note ] The temporary is
an lvalue and is used to initialize the variable named in the matching handler (15.3). The type of the throw-expression
shall not be an incomplete type, or a pointer to an incomplete type other than (possibly cv-qualified) void. Except for
these restrictions and the restrictions on type matching mentioned in 15.3, the operand of throw is treated exactly as a
function argument in a call (5.2.2) or the operand of a return statement.
Бросание копии объекта не дает никаких приимуществ перед прямым созданием экземпляра объекта.
throw exception_type("message");
Если есть исключение, которое часто бросается из разных точек программу (с одним и темже сообщением),
то есть смысл специализировать класс исключения:
throw special_exception_type();
SEV>Меняется ли ситуация если глобальный объект константный. SEV>
SEV>const A g_a;
SEV>
Нет. Не меняется.
Скрытый текст
#include <iostream>
class A
{
public:
A() { std::cerr<< "c-tor " << this <<std::endl; }
A(const A&) { std::cerr<< "copy c-tor " << this <<std::endl; }
~A() { std::cerr<< "d-tor " << this <<std::endl; }
};
const A a;
int main(int argc, char *argv[])
{
try
{
throw a;
}
catch(A& err)
{
std::cerr<<" At catch:\n"
<< "&a = " << &a <<"\n"
<< "&err= " << &err << "\n";
}
return 0;
}
При выбрасывании исключения создается копия объекта — исключения. В ряде случаев компилятор может произвести оптимизацию, и обойтись без создания временного объекта. Использование глобального объекта в качестве аргумента throw в обоих этих случаях вполне позволительно
Здравствуйте, MasterZiv, Вы писали:
MZ>Ведущие плюсологи мира уже давно доказали, что это -- плохой стиль.
С глобальными объектами они тоже уже определились
>> Про бросание копии уже написали. Но ты можешь кидать указатель, как это делается >> в MFC.
MZ>Ведущие плюсологи мира уже давно доказали, что это -- плохой стиль.
Здравствуйте, dead_ricky, Вы писали:
>>> Про бросание копии уже написали. Но ты можешь кидать указатель, как это делается >>> в MFC.
MZ>>Ведущие плюсологи мира уже давно доказали, что это -- плохой стиль.
_>Расскажите почему.
Ведущие плюсологи также осуждают goto, что не означает, что этой командой нельзя пользоваться.
В бросании по указателю есть нюанс — неизвестно, кто отвечает за время жизни объекта исключения. Если объект был создан по new, то его надо после поимки удалить. Если кидался указатель на глобальный объект, то удалять не надо. Если ты специально не обработал исключение и оно угодило в catch(...), то в первом случае происходит утечка памяти.
В MFC в интерфейсе CException есть метод Delete (точно название не помню), который надо вызвать в обработчике исключения. Кроме этого, при конструировании объекта надо выставить флажок, который определяет, надо ли убивать объект при вызове Delete или нет (для глобального объекта ессно не надо).
Т.е. если следовать правилам и программировать аккуратно, то ничего криминального не случится.
_____________________
С уважением,
Stanislav V. Zudin