В конcтрукторе некоторого класса выполняется, например, выделение памяти. Если не удалось выделить память, и следовательно, правильно проинициализировать класс, как лучше всего просигнальть об этом остальному программному коду?
Аноним wrote:
> В конcтрукторе некоторого класса выполняется, например, выделение > памяти. Если не удалось выделить память, и следовательно, правильно > проинициализировать класс, как лучше всего просигнальть об этом > остальному программному коду?
В исключительных ситуациях обычно кидают исключения.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Аноним, Вы писали:
А>В конcтрукторе некоторого класса выполняется, например, выделение памяти. Если не удалось выделить память, и следовательно, правильно проинициализировать класс, как лучше всего просигнальть об этом остальному программному коду?
метнуть исключение std::bad_alloc
!0xDEAD
Re[2]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 08:35
Оценка:
Здравствуйте, kan, Вы писали:
kan>Аноним wrote:
>> В конcтрукторе некоторого класса выполняется, например, выделение >> памяти. Если не удалось выделить память, и следовательно, правильно >> проинициализировать класс, как лучше всего просигнальть об этом >> остальному программному коду? kan>В исключительных ситуациях обычно кидают исключения.
Произошел сбой. Забросили исключение. Перехватили его. И тут вопрос, нужно ли этот непроинициализировавшийся объект удалять: delete something; ?
Здравствуйте, Какая разница, Вы писали:
КР>метнуть исключение std::bad_alloc
хотя зачем оно и так кинется если выделение идет через new
Имхо — ничего не надо делать
!0xDEAD
Re[3]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 08:39
Оценка:
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, Какая разница, Вы писали:
КР>>метнуть исключение std::bad_alloc
КР>хотя зачем оно и так кинется если выделение идет через new КР>Имхо — ничего не надо делать
Случай с выделение памяти был взят для примера. Имеется ввиду ситуация когда просто не удалось правильно проинициализировать класс.
Здравствуйте, Аноним, Вы писали:
А>В конcтрукторе некоторого класса выполняется, например, выделение памяти. Если не удалось выделить память, и следовательно, правильно проинициализировать класс, как лучше всего просигнальть об этом остальному программному коду?
В принципе, можно и без исключения.
1) Функция FinalConstruct — возвращающая код ошибки
2) Умные указатели для объектов, под которые распределяется память, + флажок успеха, к-й проверять в коде использующем класс
Умные указатели рекомендую и для случая с исключением
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Какая разница, Вы писали:
КР>>Здравствуйте, Какая разница, Вы писали:
КР>>>метнуть исключение std::bad_alloc
КР>>хотя зачем оно и так кинется если выделение идет через new КР>>Имхо — ничего не надо делать
А>Случай с выделение памяти был взят для примера. Имеется ввиду ситуация когда просто не удалось правильно проинициализировать класс.
ну тогда наверное метнуть исключение my_exception которое наследуется от std::exception и на этом
пожалуй в конструкторе ничего больше не надо
!0xDEAD
Re[5]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 08:50
Оценка:
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Какая разница, Вы писали:
КР>>>Здравствуйте, Какая разница, Вы писали:
КР>>>>метнуть исключение std::bad_alloc
КР>>>хотя зачем оно и так кинется если выделение идет через new КР>>>Имхо — ничего не надо делать
А>>Случай с выделение памяти был взят для примера. Имеется ввиду ситуация когда просто не удалось правильно проинициализировать класс.
КР>ну тогда наверное метнуть исключение my_exception которое наследуется от std::exception и на этом КР>пожалуй в конструкторе ничего больше не надо
Но остается вопрос, нужно ли этот непроинициализировавшийся класс удалять, например delete something;
(класс создавался динамически)?
Здравствуйте, Аноним, Вы писали:
А>Произошел сбой. Забросили исключение. Перехватили его. И тут вопрос, нужно ли этот непроинициализировавшийся объект удалять: delete something; ?
Если брошено исключение, то для всех переменных которые уже были сконструированы будут вызваны деструкторы
class A
{
std::string a;
std::auto_ptr<int> b;
public:
A()
: a("")
, b(new int)
{
throw std::exception();
// будут вызваны деструкторы для a и для b
}
~A()
{
// деструктор никогда не будет вызыван, поскольку конструктор никогда не завершит работу
}
};
int main()
{
try
{
std::string bb;
A a;
}
catch(std::exception&)
{
// будет вызыван деструктор для bb
}
}
Здравствуйте, Аноним, Вы писали: А>Но остается вопрос, нужно ли этот непроинициализировавшийся класс удалять, например delete something; А>(класс создавался динамически)?
заворачивай свой new CMyClass() в умный указатель
например хотя бы std::auto_ptr и спи спокойно
Тебя перестанут мучить твои сомнения
!0xDEAD
Re[4]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 08:57
Оценка:
Здравствуйте, Aera, Вы писали:
A>Здравствуйте, Аноним, Вы писали:
А>>Произошел сбой. Забросили исключение. Перехватили его. И тут вопрос, нужно ли этот непроинициализировавшийся объект удалять: delete something; ?
A>Если брошено исключение, то для всех переменных которые уже были сконструированы будут вызваны деструкторы
A>
A>class A
A>{
A> std::string a;
A> std::auto_ptr<int> b;
A>public:
A> A()
A> : a("")
A> , b(new int)
A> {
A> throw std::exception();
A> // будут вызваны деструкторы для a и для b
A> }
A> ~A()
A> {
A> // деструктор никогда не будет вызыван, поскольку конструктор никогда не завершит работу
A> }
A>};
A>int main()
A>{
A> try
A> {
A> std::string bb;
A> A a;
A> }
A> catch(std::exception&)
A> {
A> // будет вызыван деструктор для bb
A> }
A>}
A>
Aera, а если объект создавался динамически?
class A
{
std::string a;
std::auto_ptr<int> b;
public:
A()
: a("")
, b(new int)
{
throw std::exception();
// будут вызваны деструкторы для a и для b
}
~A()
{
// деструктор никогда не будет вызыван, поскольку конструктор никогда не завершит работу
}
};
int main()
{
A * a;try
{
std::string bb;
a = new A;
}
catch(std::exception&)
{
// будет вызыван деструктор для bb//нужен ли здесь delete a; ?
}
}
Re[5]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 08:59
Оценка:
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Какая разница, Вы писали:
КР>>>Здравствуйте, Какая разница, Вы писали:
КР>>>>метнуть исключение std::bad_alloc
КР>>>хотя зачем оно и так кинется если выделение идет через new КР>>>Имхо — ничего не надо делать
А>>Случай с выделение памяти был взят для примера. Имеется ввиду ситуация когда просто не удалось правильно проинициализировать класс.
КР>ну тогда наверное метнуть исключение my_exception которое наследуется от std::exception и на этом КР>пожалуй в конструкторе ничего больше не надо
это в зависимости от того как написан конструктор. на каждом уровне наследования классов объект считается созданным только после того как отработал конструктор класса. соответственно деструктор класса не вызовется если исключение вылетело из конструктора. т.е. если в конструкторе делалось что то (например тоже выделение памяти для других объектов и т.п.) до исключения ресурсы не освободятся. просто учитесь правильно писать конструкторы. _правильно_ в данном случае означает эксепшионсафе. впрочем это относиттся не только к конструкторам... например, для этого в том числе предназначена инициализация полей класса в конструкторском стиле (т.е. в стиле вызовов конструкторов подклассов). это очень хорошо сочетается с использованием автопэтээров.
еще замечание — при ошибки выделения памяти простой new возвращает 0, а не кидает эксепшн
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, Аноним, Вы писали: А>>Но остается вопрос, нужно ли этот непроинициализировавшийся класс удалять, например delete something; А>>(класс создавался динамически)?
КР>заворачивай свой new CMyClass() в умный указатель КР>например хотя бы std::auto_ptr и спи спокойно КР>Тебя перестанут мучить твои сомнения
-1
Необходимости думать это не отменяет:
int foo(std::auto_ptr<C>, std::auto_ptr<C>);
int main()
{
foo(std::auto_ptr<C>(new C()), std::auto_ptr<C>(new C()));
}
Если компилятор решит вызывать сначала два конструктора С, а только затем два конструктора std::auto_ptr<C>, то в случае, если второй конструктор кинет исключение C, получится утечка памяти и не вызыванный деструктор ~C.
--
RedApe
Re[7]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 09:19
Оценка:
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, Аноним, Вы писали:
А>>еще замечание — при ошибки выделения памяти простой new возвращает 0, а не кидает эксепшн
КР>не все так делают КР>Visual C++ например кидается как раз исключением если простой new КР>Чтобы возвратился NULL нужно new nothrow
не совсем так.
MSDN: The new and delete Operators
Beginning in Visual C++ .NET 2002, the CRT's new function (in libc.lib, libcd.lib, libcmt.lib, libcmtd.lib, msvcrt.lib, and msvcrtd.lib) will continue to return NULL if memory allocation fails. However, the new function in the Standard C++ Library (in libcp.lib, libcpd.lib, libcpmt.lib, libcpmtd.lib, msvcprt.lib, and msvcprtd.lib) will support the behavior specified in the C++ standard, which is to throw a std::bad_alloc exception if the memory allocation fails.
Normally, if you #include one of the C++ standard headers, like <new>, you'll get a /defaultlib directive in your object that will reference the appropriate C++ Standard Library according to the CRT model you used (the /M* compiler options). Generally, that will cause the linker to use the throwing operator new from the C++ Standard Library instead of the nonthrowing one from the main CRT, because the order of defaultlib directives will cause libcp.lib to be searched before libc.lib (under /ML).
кслову сказать имено потому то
delete 0;
ни чего не делает и является безопасным.
вот.
Re[8]: как остановить создание класса
От:
Аноним
Дата:
08.09.06 09:23
Оценка:
Здравствуйте, Aera, Вы писали:
A>Здравствуйте, Какая разница, Вы писали:
КР>>Здравствуйте, Аноним, Вы писали: А>>>Но остается вопрос, нужно ли этот непроинициализировавшийся класс удалять, например delete something; А>>>(класс создавался динамически)?
Если класс грамотно спроектирован — ничего удалять не надо.
КР>>заворачивай свой new CMyClass() в умный указатель КР>>например хотя бы std::auto_ptr и спи спокойно КР>>Тебя перестанут мучить твои сомнения
Возможно имелось ввиду заворачивай поля своего класса в RAII-подобные обертки?
A>Необходимости думать это не отменяет: A>
A>int foo(std::auto_ptr<C>, std::auto_ptr<C>);
A>int main()
A>{
A> foo(std::auto_ptr<C>(new C()), std::auto_ptr<C>(new C()));
A>}
A>
A>Если компилятор решит вызывать сначала два конструктора С, а только затем два конструктора std::auto_ptr<C>, то в случае, если второй конструктор кинет исключение C, получится утечка памяти и не вызыванный деструктор ~C.
+1
За это еще Майерс в далеком 199* году по рукам бил =)
Пример хрестоматийный. Хотя действительно имеет место быть.
Здравствуйте, Аноним, Вы писали:
А>Но остается вопрос, нужно ли этот непроинициализировавшийся класс удалять, например delete something; А>(класс создавался динамически)?
При появлении таких вопросов лучшее место для поиска ответа — стандарт. Вот чего пишет наш ISO/IEC 14882 в пункте 15.2, второй абзац (выделение мое):
An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution. Should a constructor for an element of an automatic array throw an exception, only the constructed elements of that array will be destroyed. If the object or array was allocated in a new-expression, the matching deallocation function (3.7.3.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.
Т.е. при исключении в конструкторе память будет освобождена автоматически.