Форум: "Прочее";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
ВнизА я и не знал... Найти похожие ветки
← →
Kerk © (2010-03-05 14:09) [40]
> @!!ex © (05.03.10 14:02) [37]
Плохой пример. TStringList сразу после создания готов к работе. Речь о случаях, когда классу требуется дополнительная инициализация.
← →
Ega23 © (2010-03-05 14:12) [41]Кстати, @!!ex ©, как ты тогда это прокомментируешь?
constructor TThread.Create(CreateSuspended: Boolean);
:)
← →
Piter © (2010-03-05 14:15) [42]@!!ex © (05.03.10 13:03) [28]
Тебя же не удивляет, что, например, TidTCPServer
все настройки идут после конструктора, а конструктор делает только базовую инициализацию.
это всего лишь подход. Который может быть иным.
Почему один правильнее другого - ты не уточняешь.
Назови плюсы твоего подхода, послушаем.
← →
GrayFace © (2010-03-05 14:43) [43]
TMemIniFile.Create(const FileName: string)
сразу открывает файл и весь его загружает. Если файл существует, но его не удасться прочесть, будет исключение.
@!!ex, что скажешь? Как бы сделал этот класс ты?
← →
oxffff © (2010-03-05 14:46) [44]
> jack128_ (05.03.10 11:18) [20]
>
> > >Теперь понятно зачем во Free проверка на Self <> nil
> > Неправильно Вам понятно :-)
>
>
> >
> > Выход по исключению из конструктора находится за пределами
>
> > операции присваивания. Поэтому воздействия на переменную-
>
> > приемник никакого.
>
>
> вообще Free имеет непосредственное отношение к сабжевому
> вопросу.
> Free было специально введено, для такого сценария работы
> с объектами:
>
> type
> TMyObj = class
> FInnerObj: TObject;
> end;
>
> constructor TMyObj.Create
> begin
> DoWork(); // тут туча кода, который может кинуть исключение
>
> FInnerObj := TObject.Create;
> end;
1. А где гарантии, что FInnerObj равен nil, для того чтобы декструктор штатно отработвал. Newinstance что обязательно установить 0?
2. Где гарантии что в деструкторе ссылка не прибитая?
:)
← →
Медвежонок Пятачок © (2010-03-05 14:48) [45]И вообще, конструктор не должен делать ничего такого, что может вызвать исключение.
Банально кончилась память.
Обломавшийся ГетМем конечно не поднимет исключения.
А конструктору тоже молчать?
:)
← →
DVM © (2010-03-05 14:50) [46]
> TMemIniFile.Create(const FileName: string)
Да можно даже было и не приводить никаких примеров. Просто надо помнить, что исключение в конструкторе объекта если там ну хоть что-то делается, например память выделяется всегда возможны. Т.е исключения в конструкторе - вещь вполне обычная.
← →
Anatoly Podgoretsky © (2010-03-05 14:54) [47]> oxffff (05.03.2010 14:46:44) [44]
Гарантия в механизме исключений. Если будет исключение, то значение не будет присвоено и Free не будет пытаться уничтожать.
← →
oxffff © (2010-03-05 14:57) [48]
> Anatoly Podgoretsky © (05.03.10 14:54) [47]
> > oxffff (05.03.2010 14:46:44) [44]
>
> Гарантия в механизме исключений. Если будет исключение,
> то значение не будет присвоено и Free не будет пытаться
> уничтожать.
Берем перекрываем аллокатор newinstance без очистки на 0 для неуправляемых объектов. Получаем исключение на free. Гарантий нет!!!
← →
Anatoly Podgoretsky © (2010-03-05 15:05) [49]> oxffff (05.03.2010 14:57:48) [48]
Ты про стеклянный член слышал?
← →
oxffff © (2010-03-05 15:05) [50]
> Anatoly Podgoretsky © (05.03.10 15:05) [49]
> > oxffff (05.03.2010 14:57:48) [48]
>
> Ты про стеклянный член слышал?
Не я просто умные книжки читаю. Слышали про такие?
← →
Медвежонок Пятачок © (2010-03-05 15:21) [51]по моему все забыли для чего существуют исключения.
это не ошибки, а элегантный способ избавится от многоэтажных ифов
← →
Kerk © (2010-03-05 15:23) [52]
> Медвежонок Пятачок © (05.03.10 15:21) [51]
Ну да. Исключение - это совершенно штатная ситуация.
← →
Дмитрий С © (2010-03-05 15:27) [53]
> Выход по исключению из конструктора находится за пределами
> операции присваивания. Поэтому воздействия на переменную-
> приемник никакого.
Эта проверка во Free по-моему задумана вот для чего:
TSomeObject = class
FList1, FList2: TList;
constructor Create;
destructor Destroy; override;
end;
constructor TSomeObject.Create;
begin
FList1 := TList.Create; // Предположим в этой строке поднялось исключение.
FList2 := TList.Create;
end;
destructor TSomeObject.Destroy;
begin
FList1.Free;
FList2.Free; // Тогда в этой строке исключения не будет, т.к. метод FList2.Free проверит FList2 на nil перед вызовом его деструктора.
end;
А вы о чем подумали?:)
> Ega23 © (05.03.10 10:59) [13]
> Разницу между Free и Destroy осчусчаешь? :)
Конечно :)
← →
@!!ex © (2010-03-05 15:29) [54]> [43] GrayFace © (05.03.10 14:43)
Неудачный пример.
В первую очередь потому, что отличается от общего стиля остальной бибилиотеки, что плохо.
Если делать в общем стиле, нужно делать через LoadFromFile.
Я бы сделал через LoadFromFile,SaveToFile.
Еще раз:
Если бы у меня возникла необходимость сделать что-то в Create, я бы это сделал. И в принципе сейчас делаю. Но не считаю что это правильно. Это проще.
← →
KSergey © (2010-03-05 15:32) [55]> oxffff © (05.03.10 14:57) [48]
> Берем перекрываем аллокатор newinstance без очистки на 0
> для неуправляемых объектов. Получаем исключение на free.
> Гарантий нет!!!
Речь про штатное поведение дельфи.
Если сделал говно - не надо другим его тыкать.
← →
Dimka Maslov © (2010-03-05 15:33) [56]
> ... что если поднять исключение в конструкторе, то автоматически
> вызовется деструктор destroy.
А ещё, оказывается, можно в конструкторе вызывать виртуальные методы. И многое другое, что написано в анналах и нельзя в других языках. Надо только прочитать и уяснить.
> не только, в с++ тоже можно.
Только при этом не будет вызван деструктор, что приведёт к утечке памяти, если до возникновения исключения в конструкторе выделялась память через new.
← →
KSergey © (2010-03-05 15:34) [57]> Дмитрий С © (05.03.10 15:27) [53]
> Эта проверка во Free по-моему задумана вот для чего:
Это все уже написано в [20]
Зачем писать еще раз?
← →
Дмитрий С © (2010-03-05 15:36) [58]
> jack128_ (05.03.10 11:18) [20]
Не успел прочитать, ответил сам:)
> destructor TFoo.Destroy;
> ...
> if Assigned(FBar) then
> FBar.Free;
> ...
> end;
>
> или
>
> destructor TFoo.Destroy;
> ...
> if Assigned(FBar) then
> FreeAndNil(FBar);
> ...
> end;
Тут IF скорее всего добавлен для понятности. Что при вызове деструктора, логикой так заложено, что FBar может быть nil.
Ну, например, если FBar с самого начала существования объекта не нужен, а инициализируется впоследствии. Как-то так.
← →
Kerk © (2010-03-05 15:39) [59]
> @!!ex © (05.03.10 15:29) [54]
>
> > [43] GrayFace © (05.03.10 14:43)
>
> Неудачный пример.
> В первую очередь потому, что отличается от общего стиля
> остальной бибилиотеки, что плохо.
Причем тут библиотека вообще? VCL - эталон?
← →
@!!ex © (2010-03-05 15:48) [60]> [59] Kerk © (05.03.10 15:39)
>
> > @!!ex © (05.03.10 15:29) [54]
> >
> > > [43] GrayFace © (05.03.10 14:43)
> >
> > Неудачный пример.
> > В первую очередь потому, что отличается от общего стиля
>
> > остальной бибилиотеки, что плохо.
>
> Причем тут библиотека вообще? VCL - эталон?
Delphi без VCL имеет мало ценности.
Писать в разных стилях в пределах одного проекта - плохо.
← →
oxffff © (2010-03-05 15:50) [61]
> KSergey © (05.03.10 15:32) [55]
> > oxffff © (05.03.10 14:57) [48]
> > Берем перекрываем аллокатор newinstance без очистки на
> 0
> > для неуправляемых объектов. Получаем исключение на free.
>
> > Гарантий нет!!!
>
> Речь про штатное поведение дельфи.
> Если сделал говно - не надо другим его тыкать.
Причем здесь говно?
В записи активации в стеке инициализируется только управляемые объекты.
В остальных мусор.
← →
Игорь Шевченко © (2010-03-05 15:58) [62]KSergey © (05.03.10 15:32) [55]
> Речь про штатное поведение дельфи.
Штатным поведением Delphi запрещено перекрывать NewInstance ?
← →
Alkid © (2010-03-05 16:01) [63]Народ, хорош на C# и С++ наезжать! Выброс исключение в конструкторе у них - совершенно нормальная идиома, против которой нет никаких законов.
Более того, в C++ на этот счет все устроено достаточно логично: при выбросе исключения из конструктора вызываются деструкторы всех УЖЕ СКОНСТРУИРОВАННЫХ подобъектов.
Т.е:
class A
{
public:
A();
~A();
}
class A2
{
public:
A2();
~A2();
}
class B : public A
{
public:
B () { throw 0; }
~B();
}
...
B b();
Цепочка вызовов будет: A(), A2(), B() с выбросом, ~A2(), ~A().
И никаких утечек!
Читайте Стандарт и учите матчасть.
Или не критикуйте то, чего не знаете!
← →
Alkid © (2010-03-05 16:01) [64]Поправка к предыдущему сообщению:
...
class B : public A, public A2
...
← →
Alkid © (2010-03-05 16:03) [65]А касаемо вызова виртуальной функции в конструкторе - господа, как вы намереваетесь вызывать функцию для объекта, который еще не создан, а?
← →
Игорь Шевченко © (2010-03-05 16:07) [66]
> А касаемо вызова виртуальной функции в конструкторе - господа,
> как вы намереваетесь вызывать функцию для объекта, который
> еще не создан, а?
Конструктор вызывается, когда объект уже создан, но не "сконструирован" :)
Вызвать виртуальную функцию в этот момент ничего не мешает, таблица виртуальных функций уже находится на нужном месте.
← →
@!!ex © (2010-03-05 16:13) [67]> [63] Alkid © (05.03.10 16:01)
Вы читали ссылку которую я давал или просто так написать решили?
← →
Alkid © (2010-03-05 16:14) [68]
> Игорь Шевченко © (05.03.10 16:07) [66]
Я о другом. Концепция класса с конструкторами и деструкторами дает программисту определенные инварианты, на которые он может опираться. Например, что вызов метода объекта может быть произведен только после того, как объект будет сконструирован, т.е. когда конструктор завершит свою работу.
Рассмотрим пример:
class A
{
public:
A() { F(); }
virtual void F() { printf("A::A()");}
}
class B : public A
{
public:
B() { message = "Hello, World!"; }
virtual F() { printf("%s \n", message); }
private:
char* message;
}
Согласно стандарту в A::A() будет вызван метод A::F(), что сохраняет озвученный выше инвариант. Если бы в A::A() вызывалась самая перегруженная реализация, т.е. B::F(), то мы бы имели вызов метода класса B до вызова конструктора класса. В приведенном примере это будет означать стрельбу по нулевому указателю, т.е. AV.
Так что этот пункт в Стандарте появился неслучайно, и очень продумано.
← →
Alkid © (2010-03-05 16:16) [69]
> @!!ex © (05.03.10 16:13) [67]
Искренне пытался, но она у меня не открылась.
← →
@!!ex © (2010-03-05 16:20) [70]> [69] Alkid © (05.03.10 16:16)
Суть ссылки:
По стандарту исключение в конструкторе допустимо и не приведет к ошибка.
Но далеко не все современные распространенные компиляторы это правильно обрабатывают.
P.S.
Про то, что не существуют компилятора полностью реализцющего стандарт С++ вы наверняка в курсе.
← →
tesseract © (2010-03-05 16:22) [71]
> Про то, что не существуют компилятора полностью реализцющего
> стандарт С++ вы наверняка в курсе.
Ну работать-то нужно :-D
← →
DVM © (2010-03-05 16:24) [72]
> @!!ex © (05.03.10 16:20) [70]
> Но далеко не все современные распространенные компиляторы
> это правильно обрабатывают.
У gcc с этим точно нет проблем.
← →
tesseract © (2010-03-05 16:37) [73]
> У gcc с этим точно нет проблем.
Может всё-таки g++ ? Gcc не совсем компилятор, а скорее фронтэнд.
← →
Игорь Шевченко © (2010-03-05 16:41) [74]Alkid © (05.03.10 16:14) [68]
> Согласно стандарту в A::A() будет вызван метод A::F()
в С++ порядком вызова конструкторов разве можно управлять ? А в Delphi можно.
← →
@!!ex © (2010-03-05 16:42) [75]> [72] DVM © (05.03.10 16:24)
Судя по статье у MS с этим проблема есть.
Проверять пока повода не было.
← →
Дмитрий С © (2010-03-05 16:44) [76]Хотел задать вопрос: "Для чего нужна эта таблица виртуальных методов? А точнее почему она создается в run-time? Разве компилятор при компиляции не может определить где находится код того или иного метода?".
Пока писал - сам понял. Заодно понял откуда взялось название "виртуальный". Сегодня день открытий прям.
← →
Игорь Шевченко © (2010-03-05 16:47) [77]
> А точнее почему она создается в run-time?
Она не создается в ран-тайм. А вот присвоение ее конкретному экземпляру объекта происходит именно в ран-тайм.
← →
Alkid © (2010-03-05 16:51) [78]
> @!!ex © (05.03.10 16:20) [70]
По ссылке бред написан. Не читайте его.
Вот пример:
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
class B
{
public:
B()
{
printf("B::B()\n");
}
~B()
{
printf("B::~B()\n");
}
};
class A : public B
{
public:
A()
{
printf("A::A()\n");
throw 0;
}
~A()
{
printf("A::~A(), Should never get here.\n");
}
void * operator new(size_t size)
{
printf("Allocating\n");
return malloc(size);
}
void operator delete(void* p)
{
printf("Deallocating\n");
free(p);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
printf("Starting.\n");
try
{
A* a = new A();
printf("Like a normal work. Should never get here\n");
}
catch(...)
{
printf("Error!\n");
return 1;
}
printf("Finishing like a normal work. Should never get here.\n");
return 0;
}
Вот выход из примера:
Starting.
Allocating
B::B()
A::A()
B::~B()
Deallocating
Error!
Все нормально создается, уничтожается и освобождается.
← →
Alkid © (2010-03-05 16:55) [79]
> Игорь Шевченко © (05.03.10 16:41) [74]
> в С++ порядком вызова конструкторов разве можно управлять? А в Delphi можно.
Вот потому-то и нельзя вызывать виртуальные методы из базовых классов, что нельзя управлять порядком вызова конструкторов. Если понимать правила С++, то все становится достаточно логично и очевидно.
Кстати, это уже отдельная тема - порядок вызова конструкторов это тоже инвариант, который не следует нарушать. То, что дельфи позволяет вызывать конструктор базового класса произвольным образом, или даже вообще его не вызывать - это глюк.
← →
Игорь Шевченко © (2010-03-05 16:57) [80]Alkid © (05.03.10 16:55) [79]
> Вот потому-то и нельзя вызывать виртуальные методы из базовых
> классов
Вот потому и в стандарте приняли, что нельзя управлять порядком вызова.
> То, что дельфи позволяет вызывать конструктор базового класса
> произвольным образом, или даже вообще его не вызывать -
> это глюк.
Это не глюк, а свойство языка. Точно также можно сказать, что слово friend в C++ это глюк, потому что в Delphi его нет (и близкого понятия - тоже).
Страницы: 1 2 3 4 5 6 вся ветка
Форум: "Прочее";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.63 MB
Время: 0.061 c