C++/CLI vs C#
, Ваше мнение.
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.141] |
|
|
| Страницы: (4) 1 2 [3] 4 все ( Перейти к последнему сообщению ) |
C++/CLI vs C#
, Ваше мнение.
|
Сообщ.
#31
,
|
|
|
|
На самом деле я наврал конечно, объект будет располагаться все равно в куче, но вести себя будет как объект расположенный в стеке (семантика стека). В конце метода компилером будет вставлен код вызова финализатора объекта. Так что выглядеть это будет так...
![]() ![]() void Foo() { SqlConnection connection (myConnString); SqlDataReader reader = connection.ExecuteReader(); // ... работаем } // вызовутся финализаторы Добавлено Цитата Loviard @ Однако я опять наврал В конце метода компилером будет вставлен код вызова финализатора объекта Вызовется именно IDisposable.Dispose, просто в C++/CLR он имеет синтаксис деструктора. Вообще там все так интересно построено...Вот мой код класса: ![]() ![]() public ref class A { public: A() { Console::WriteLine("A::A();"); } ~A() // деструктор, а на самом деле Dispose { Console::WriteLine("A::~A();"); }//*/ !A() // финализатор { Console::WriteLine("A::!A();"); }//*/ void f() { Console::WriteLine("A::f();"); } }; А вот то, что из него сотворил компилятор: (Рефлектор пока только MC++ знает ) ![]() ![]() public __gc class A : public IDisposable { // Methods private: void __gc* !A() // компилер превратил в обычный метод, добавил возвращаемый тип, хотя в коде синтаксис этого не требует... { Console::WriteLine(S"A::!A();"); } public: A() { Console::WriteLine(S"A::A();"); } private: void __gc* ~A() { Console::WriteLine(S"A::~A();"); } public: sealed override void __gc* Dispose() { this->Dispose(true); GC::SuppressFinalize(this); } protected: virtual void __gc* Dispose([MarshalAs(UnmanagedType::U1)] Boolean __gc* flag1) { if (flag1) { this->~A(); } else { try { this->!A(); } finally { base->Finalize(); } } } public: void __gc* f() { Console::WriteLine(S"A::f();"); } protected: override void __gc* Finalize() { this->Dispose(false); } }; Дописав в класс "деструктор" ~A() компилер автоматически порождает мой класс от IDisposable и добавляет код его реализации... |
|
Сообщ.
#32
,
|
|
|
|
Loviard, thx. Сбор мусора как был недетерминированым таким и остался по своей сути, ожидать чего то другого было бы странно при размещении объектов в управляемой куче.
|
|
Сообщ.
#33
,
|
|
|
|
А вот реализация метода f(), в котором я деструктор проверял:
мой код: ![]() ![]() void f() { A a; a.f(); } Рефлектор: ![]() ![]() public private: static void __gc* modopt(CallConvCdecl __gc*) f() { A __gc* a = 0; A __gc* modopt(IsConst __gc*) a2 = __gc new A(); try { a = a2; a->f(); } fault { a->Dispose(); } a->Dispose(); } Объект конечно удален не будет, но путем нескольких извратов компилер вызовет Dispose... |
|
Сообщ.
#34
,
|
|
|
|
Loviard, вот смотри какая любопытная фича, при выходе из области видимости объекта A,
Например код метода f в классе B ![]() ![]() void f() { A a; a.f(); } вызывается его деструктор, но не Dispose, а это наталкивает на одну очень интересную, на мой взгляд мысль, что если пользоваться "семантикой стека" с объектом вроде SqlConnection, то это в конечном итоге, привидет к эффекту достигаемому, когда Close или Dispose вообще явно не вызываются. Как следствие Close отработает при вызове Dispose тогда когда этот объект будет размещен в очередь для выполнения финалайзера... а это произойдет только тогда когда сборщик мусора определит, что объект является мусором. При этом реальное освобождение памяти вообще произойдет при следующем проходе GC. Добавлено Loviard ты опередил, я только хотел посмотреть во-что это скомпилится. Оказывается Dispose таки вроде как вызывается. |
|
Сообщ.
#35
,
|
|
|
|
Не... при выходе из метода вызовется то как раз Dispose, просто в С++/CLI по синтакису Dispose является деструктором (а финалайзер отдельно). Более того, они как-то странно это сделали. Ты можешь отнаследовать класс от IDisposable, но компилер запретит тебе написать метод с названием Dispose. Тебе только можно написать метод ~A() ...А компилер сам реализetn Dispose и вызовет в нем ~A() как показано выше. А при выходе из метода вызовет именно IDisposable.Dispose
|
|
Сообщ.
#36
,
|
|
|
|
Цитата Loviard @ компилер вызовет Dispose... И закроет соединение: Вот код из SqlConnection ![]() ![]() protected: override void __gc* Dispose(Boolean __gc* disposing) { if (disposing) { this->_userConnectionOptions = 0; this->_poolGroup = 0; this->Close(); } this->DisposeMe(disposing); base->Dispose(disposing); } |
|
Сообщ.
#37
,
|
|
|
|
Цитата juice @ Loviard ты опередил, я только хотел посмотреть во-что это скомпилится. Оказывается Dispose таки вроде как вызывается. Тайный заговор Микрософта раскрыт... |
|
Сообщ.
#38
,
|
|
|
|
Цитата Loviard @ Более того, они как-то странно это сделали. Ты можешь отнаследовать класс от IDisposable, но компилер запретит тебе написать метод с названием Dispose. Это очевидно помоему, нельзя и рыбу есть и на велосипеде кататься |
|
Сообщ.
#39
,
|
|
|
|
Ну и само собой вполне корректно работает следующая ситуация, что сразу сводит на нет все безопасность:
![]() ![]() A^ f() { A a; a.f(); return %a; } void g() { A^ a = f(); a.f(); // !!! все вполне корректно :) } Вот вам и область видимости переменной |
|
Сообщ.
#40
,
|
|
|
|
Цитата Loviard @ Ну и само собой вполне корректно работает следующая ситуация, что сразу сводит на нет все безопасность: ![]() ![]() A^ f() { A a; a.f(); return %a; } void g() { A^ a = f(); a.f(); // !!! все вполне корректно :) } Вот вам и область видимости переменной ![]() Угу На сарае написано XXX, а там дрова лежат... вот так и тут по ходу выходит ... |
|
Сообщ.
#41
,
|
|
|
|
Чего ты прикидываешься? Несовместимы - это когда ты пишешь конструкцию ANSI C++, а она в режиме С++/CLI превращается в конструкцию С++/CLI - т.е. теряется возможность в одной программе использовать конструкции из обоих языков так, как они задумывались. Но ведь это не так, а значит - языки совместимы. Цитата juice @ Цитата Loviard @ Ну и само собой вполне корректно работает следующая ситуация, что сразу сводит на нет все безопасность: ![]() ![]() A^ f() { A a; a.f(); return %a; } void g() { A^ a = f(); a.f(); // !!! все вполне корректно :) } Вот вам и область видимости переменной ![]() Угу На сарае написано XXX, а там дрова лежат... вот так и тут по ходу выходит ... ![]() Да не, походу выходит, что управляемые программисты на ворнинги внимания обращают.. Ну, тогда Бог с вами, возвращайте указатели на локальные автоматические объекты, если вам так хочется, а потом плюйтесь на язык. Адью. |
|
Сообщ.
#42
,
|
|
|
|
Hryak, да мы не плюемся. Ты по моему не правильно толкуешь. Я например считаю C++/CLI вполне оптимальным выбором в некоторых ситуациях. Просто я думал ты волшебник и покажешь как объект SqlConnection поместить на стеке, а не в куче, а потом еще и коректно освободить память не вызывая Close. А ты просто описался видимо или думал о "стеке" рассмотренном выше.
|
|
Сообщ.
#43
,
|
|
|
|
Цитата juice @ Просто я думал ты волшебник и покажешь как объект SqlConnection поместить на стеке Читаем внимательно в C++/CLI vs C# (сообщение #1945345) Кавычки видим? Я же их не случайно поставил, я прекрасно знаю, что такие объеты по-любому размещаются в управляемой куче, речь шла именно про семантику стека, а не про сам стек. Добавлено Цитата juice @ Я например считаю C++/CLI вполне оптимальным выбором в некоторых ситуациях. Чтобы была ясность - я не считаю, что C++/CLI - оптимальный выбор во всех ситуациях. Я просто защищаю конкретную уникальную фичу этого языка, которую вы недооцениваете, имхо. |
|
Сообщ.
#44
,
|
|
|
|
Цитата Hryak @ Ты давай повежливее... Ты сам-то не прикидываешься? - ты понял что я имел в виду, более того, я это потом еще и объяснил подробно. В общем ты просто придираешься к словам.Чего ты прикидываешься? Цитата Hryak @ Ты чего кипятишься? Конечно я заметил варнинг, но это просто костыль компилятора. Потому-что код, который я привел вполне корректный. Объект располагается в управляемой куче, я увеличил количество ссылок на него, поэтому могу без задних мыслей его использовать в другом методе. Да не, походу выходит, что управляемые программисты на ворнинги внимания обращают.. Ну, тогда Бог с вами, возвращайте указатели на локальные автоматические объекты, если вам так хочется, а потом плюйтесь на язык. Адью. Цитата Hryak @ Это не та фича, которая повлияла бы хоть на какое-то решение в его пользу. Фичи, ради которых, его действительно стоит использовать, я приводил выше... Чтобы была ясность - я не считаю, что C++/CLI - оптимальный выбор во всех ситуациях. Я просто защищаю конкретную уникальную фичу этого языка, которую вы недооцениваете, имхо. |
|
Сообщ.
#45
,
|
|
|
|
Цитата Loviard @ Это не та фича, которая повлияла бы хоть на какое-то решение в его пользу. Согласен. По сабжу. ИМХО, вариант с auto_handle, выглядит естественней и действительно является классной фичей, равноценно-удобного аналога которого в шарпе дейтсвительно нет. Покрайней мере, на мой неискушенный взгляд, код в данном контексте получается ясный и явно демонстрирует намерения разработчика. |