J>>Строго говоря GC в С++ есть, только реально никому не нужен, поэтому традиционно не используется.
J>>Твои слова? NBN>Тут нет ни слова про поддержку. Поддержка будет в следующем стандарте.
Ну так и у меня не слова про поддержку, если искать именно это слово
Я просто проиллюстрировал, как выглядит наш диалог со стороны.
Хотя... если что-то "есть в С++", это, имхо, значит, что есть именно поддержка со стороны языка.
Но это уже терминологических спор, который, я думаю, никому затевать неинтересно.
NBN>Это из разряда — в С можно писать в ООП стиле, включая использование виртуальных функций, но вот поддежки ООП в языке нет.
А что, есть? Или я опять тебя не понял?
J>>Особенно интересно в свете развернувшейся дискуссии, что ты вкладываешь в слово "строго" выше? NBN>Строго — значит оно есть. А выделил это слово чтобы показать что есть нюансы использования. Классический пример — если будешь хранить указатели в разобранном виде или выделять память нестандартным образом — ничего не будет работать.
ОК, принято. (Хоть и противоречит математическому смыслу слова "строго")
NBN>>>Ну и что? Я могу привести пару дурацких примеров наподобии твоего — доказывающих, что нет смартпоинтеров. NBN>>>Но они есть J>>Да, они есть, а GC нет. J>>Потому что GC — это "создал и забыл", с гарантией, что никогда не получишь указателей в никуда или в мертвый объект. NBN>Ну я примерно так и писал в тестовом проекте. Выделял-выделял-выделял память и не заботился о её удалении и всё работает зашибись. Единственное что я когда пишу — понимаю, что происходит и соблюдаю условия необходимые для работы gc.
Т.е. ты никогда не передавал ссылки на внутренности, только на объекты целиком?
J>>А GC в стиле "создал и не дай бог забудешь, где и что и как с ним обращаться" — такой GC действительно никому не нужен, разве что в качестве back-end управляемой среды. NBN>C++ у нас феррари
Вот о чем и речь. На феррари на дачу не поедешь. Это к вопросу об обсуждаемых пределах С++.
You will always get what you always got
If you always do what you always did
Re[4]: Пределы C++
От:
Аноним
Дата:
04.06.08 10:26
Оценка:
Здравствуйте, NikeByNike, Вы писали:
NBN>Здравствуйте, Аноним, Вы писали:
А>>Раньше нужно было не забыть delete/free, а теперь нужно знать в деталях как работает GC
NBN>В нормальном С++ коде не должно быть слов delete и free.
Речь о другом, о том что с GC нужно знать его принцип работы иначе можна быстро за#$%ть память, а в некоторых случаях и еще хуже необходимо самому звать Dispose. То есть реально легче прогеру не стало, так как нужно помнить много ньюансов GC, а в С++ управление памятью намного проще.
Вот если бы GC сам по себе эффективно управлял памятью и не нужно было знать принцип его работы то тогда согласен
Здравствуйте, NikeByNike, Вы писали:
V>>В результате получается, что писать что-то кроссплатформенное нереально сложно, приходится выдумывать ненужные слои абстракции и обрастать макросами.
NBN>Вообще-то практика показывает, что писать на С++ кроссплатформенные проги как раз проще, чем на других языках.
Здравствуйте, NikeByNike, Вы писали:
NBN>Здравствуйте, jazzer, Вы писали:
NBN>>>Ойли, ты можешь получить gc-указатель на объект созанный на стеке? J>>Я же сказал, расставь __gc по вкусу. NBN>А это что?
J>>Естественно, подразумевается, что s создан управляемым. J>>Прошу прощения, если запутал тебя.
NBN>Если я правильно понял, то всё будет выглядеть так:
NBN>
NBN>struct S
NBN>{
NBN> int* i;
NBN> S()
NBN> {
NBN> i = gcnew int(1);
NBN> }
NBN>};
NBN>int* f()
NBN>{
NBN> S s;
NBN> return s.i;
NBN>}
NBN>int main()
NBN>{
NBN> int* pi = f();
NBN>}
NBN>
Не совсем, я имел в виду
struct S
{
int i;
};
int* f() // как-то поменять
{
S* s = gcnew S(); // правильный синтаксис?return &s.i; // как-то поменять
}
Здравствуйте, NikeByNike, Вы писали:
E>>О том, что приведенные в качестве примера разработанные тобой программы, работающие на С++ c GC NBN>Где я приводил такой пример???
Я подумал, что в них применялся GC
E>>не являются достаточным опровержением тезиса о том, что в C++ нет GC. NBN>Ага, если код есть и работает, это не является доказательством его наличия?
У меня есть масса C++ного кода, который работает и использует сериализацию C++ классов. Что ни в коем случае не доказывает наличия сериализации в C++.
Следуя определенным правилам можно написать программу на языке C++, которая будет работать под GC. Но это будет конкретная программа, а вовсе не факт того, что в C++ появился GC.
E>>Но в общем случае для C++ GC до сих пор нет. NBN>Как раз в общем он есть. Просто не используется по нескольким причинам (скорость, нераспространённость, отсуствие поддержки со стороны стандартных либ).
Если по твоим же словам с STL он не дружит, значит его и нет.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, NikeByNike, Вы писали:
J>>>А это означает, что GC в том смысле, в котором он рулит в управляемых языках, в С++ нет. RO>>И не может быть. NBN>Хоть 10 раз можно повторить, это бесполезно пока есть конкретные работающие примеры.
Пока в C++ можно преобразовать void* в int, который писать в файлы и читать оттуда, полнофункциональная GC невозможен.
Мне нравится подход C++/CLI: второй тип указателей и соответствующий тип ссылок. Но вместо того комитет решил требовать от GC смотреть во всякие указателеопасные места вроде целочисленных переменных подходящего размера. Например, это должно работать:
// в недрах библиотеки
intptr_t getX()
{
return reinterpret_cast<intptr_t>(new X);
// ссылки на объект остались, GC его не тронет!
}
// код пользователяreinterpret_cast<X *>(getX())->doSomething();
// а вот теперь можно и удалить
Здравствуйте, Roman Odaisky, Вы писали:
NBN>>Вообще-то практика показывает, что писать на С++ кроссплатформенные проги как раз проще, чем на других языках.
RO>Например, чем на Java?
Любимая шутка наших ребят разрабатывающих какие-то части ?явамашины?: "Вы всё ещё думаете, что ява кросплатформенна?"
Хотя ява конечно тоже рулит. С другой стороны С++ способен залесть в большее количество щелей и в частности на нём можно без проблем писать на покеты
Здравствуйте, remark, Вы писали:
R>Не пользуются ими C++ программисты видимо просто из "исторических" причин. Типа мы же 20 обходились без GC, а теперь Вы нам пытаетесь сказать, что без него нельзя писать работающие программы и жить вообще R>Хотя можно и писать на C++, и использовтаь GC одновременно — достаточно поглядеть на список пользователей Boehm GC.
В языке D использовался консервативный GC, который считал указателями все, что было похоже на указатели. После чего пользователи стали жаловаться на неправильную работу программ, обрабатывающих большие массивы вещественных данных -- определенные значения float-ов и double-ов воспринимались таким GC как указатели и соответствующим образом обрабатывались. После чего в D были добавлены специальные функции, позволяющие пометить область памяти как гарантированно не содержащую указателей.
Аналогичные проблемы могут возникнуть при использовании криптографии -- фрагменты криптоключей, криптотекста и подписей/хешей могут быть очень похожы на указатели, что снесет башку консервативному GC.
Согласись, что GC, в котором нужно явно указавать характер данных в определенных областях памяти, не сильно похож на GC из C#/Java.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, jazzer, Вы писали:
J>Хотя... если что-то "есть в С++", это, имхо, значит, что есть именно поддержка со стороны языка.
C++ старается как можно больше функций отдать на откуп библиотекам. В случае gc у него это получается недостаточно красиво — хотя данную функциональность можно использовать — из-за недостатока сахара это получается не очень красиво. Так же как с виртуальными функциями языка С.
J>Т.е. ты никогда не передавал ссылки на внутренности, только на объекты целиком?
Эээ, если так сходу, то либо константную ссылку для кратковременного использования, либо (если мембер должен шарится) через умный указатель.
NBN>>C++ у нас феррари J>Вот о чем и речь. На феррари на дачу не поедешь. Это к вопросу об обсуждаемых пределах С++.
Доказательства по аналогиям.
Goal
• Support
– Conservative Garbage Collection
– Reachability-based leak detection
• Which becomes more critical with quick_exit()
• By
– Giving undefined behavior to programs that hide pointers.
– Providing a small API to “unhide” pointers.
– Providing a small API to make collection less conservative.
E>Я подумал, что в них применялся GC
Я этого не говорил.
E>У меня есть масса C++ного кода, который работает и использует сериализацию C++ классов. Что ни в коем случае не доказывает наличия сериализации в C++.
Ну сейчас буст включат в стандарт и будет тебе сериализация в С++.
E>Следуя определенным правилам можно написать программу на языке C++, которая будет работать под GC. Но это будет конкретная программа, а вовсе не факт того, что в C++ появился GC.
Налицо явное нарушение логики...
E>Если по твоим же словам с STL он не дружит, значит его и нет.
Не значит.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Не пользуются ими C++ программисты видимо просто из "исторических" причин. Типа мы же 20 обходились без GC, а теперь Вы нам пытаетесь сказать, что без него нельзя писать работающие программы и жить вообще R>>Хотя можно и писать на C++, и использовтаь GC одновременно — достаточно поглядеть на список пользователей Boehm GC.
E>В языке D использовался консервативный GC, который считал указателями все, что было похоже на указатели. После чего пользователи стали жаловаться на неправильную работу программ, обрабатывающих большие массивы вещественных данных -- определенные значения float-ов и double-ов воспринимались таким GC как указатели и соответствующим образом обрабатывались. После чего в D были добавлены специальные функции, позволяющие пометить область памяти как гарантированно не содержащую указателей.
E>Аналогичные проблемы могут возникнуть при использовании криптографии -- фрагменты криптоключей, криптотекста и подписей/хешей могут быть очень похожы на указатели, что снесет башку консервативному GC.
E>Согласись, что GC, в котором нужно явно указавать характер данных в определенных областях памяти, не сильно похож на GC из C#/Java.
Да. Не похож. Прострелить ногу и голову одним выстрелом всё ещё можно.
Помниться сам Boehm как-то говорил, что если Вы хотите его сломать, то не вопрос — у Вас получится Но если если Вы ставите целью его использовать, а не ломать, то он будет работать хорошо, при этом надо понимать что это такое и как работает (последнее в принципе справедливо и для "GC из C#/Java", хотя наверное в меньшей степени).
void declare_no_pointers( char* p, size_t n ) throw()
Effects:
The n bytes starting at p no longer contain traceable pointer locations, independent of their type. Hence pointers located there may no longer be dereferenced. [Note: This may be used to inform a garbage collector or leak detector that this region of memory need not be traced.]
Throws:
Throws no exceptions. [Note: Under some conditions implementations may need to allocate memory. However the request can be ignored if memory allocation fails. -- end note]
Requires:
No bytes in the specified range may have been previously registered with declare_no_pointers(). If the specified range is in an allocated object, then it must be entirely within a single allocated object. The object must be live until the corresponding undeclare_no_pointers() call. [Note: In a garbage-collecting implementation, the fact that a region in an object is registered with declare_no_pointers() should not prevent the object from being collected. --end note]
void undeclare_no_pointers( char* p, size_t n ) throw()
Effects:
Prepares an object containing a range registered with declare_no_pointers() for destruction. It must be called before the lifetime of the object ends. It has no other effect. It does not recreate any traceable pointer locations in the object.
Requires:
The same range must previously have been passed to declare_no_pointers().
И вдобавок для кода, который может "прятать" указатели:
void declare_reachable( void* p ) throw(std::bad_alloc)
Effects:
If p is not null, the complete object referenced by p is subsequently declared reachable (see 3.7.3.3).
Throws:
May throw std::bad_alloc if the system cannot allocate additional memory that may be required to track objects declared reachable.
Requires:
The argument p shall be a safely derived pointer.
template < typename T >
T* undeclare_reachable( T* p ) throw()
Returns:
A safely derived copy of p. The result will compare equal to p.
Effects:
Once the number of calls to undeclare_reachable(p) equals the number of calls to declare_reachable(p) for all non-null p referencing the argument is no longer declared reachable (see [above section]). When this happens, pointers to the object referenced by p may not be subsequently dereferenced unless they are safely derived. [Note: Since the returned pointer is safely derived, it may be used to access the referenced object, even if previously no safely derived pointer existed. -- end note]
Requires:
If p is not null, declare_reachable(p) was previously called, and shall be live from the time of the call until the last undeclare_reachable(p) call on the object.
Здравствуйте, NikeByNike, Вы писали:
RRO>>Разве что GC может (иногда) решить проблему циклических ссылок, которые сложно отследить с помощью «умных» указателей. Но можно. Еще в 2003 г. в списке рассылки Boost показался cyclic_ptr, который их-таки отслеживал. Поступал он очень просто: вызывал **this = **this, что приводило к копированию всех подобъектов — в том числе подобъектов типа cyclic_ptr, чьи операторы присваивания делали то же самое для своих объектов и таким образом обнаруживали циклы. Но требование копируемости класса всё портило.
NBN>Лично я не сталкивался с циклическими ссылками уже лет 6, с тех пор как узнал что это. Со всем сталкивался, с целым зверинцем разнообразных багов, со всего света. NBN>Что я делаю не так? :))
Может быть. Но речь-то о (не)возможности искать их в языках без GC, а не о правильном проектировании владения.
NBN>Кстати, практически в любом более-менее серьёзном проекте существует детектор ликов, который должен сообщать о таких случаях.
Ну то понятно, но он всё равно не даст 100% гарантии.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, Константин Л., Вы писали:
КЛ>>>>а так, что interlockedincrement/decrement не нужен как класс. а сколько они стоят для smp?
CS>>>А как делать блокировку managed heap при new из разных потоков?
КЛ>>Это максимум один exchange/increment на выделение.
CS>Значит таки нужен... идем тогда дальше.
CS>Когда тебе мусор собрать надо ты останавливаешь все потоки (stop the world в общем случае). CS>В связи с этим возникает вопрос: что лучше много маленьких interlockedincrement/decrement или один но толстый stop-the-world?
Во-первых, аллокация/деаллокация памяти и GC — это разные вещи, предназначенные для разного. Да, Java преподносит всё в одном флаконе: язык_виртуальная_машина_библиотека_подсистема_пямяти_управление_временем_жизни_объектов. Но вообще никто не запрещает (и это сильная сторона С++) использовать для управления памятью одно решение, а для управления временем жизни — другое, и произвольно их комбинировать.
Для управления памятью можно использовать: хип, хип на поток, хип с перемещаемыми объектами, регионы, ропы, аллокаторы для объектов фикмированного размера и т.д.
Для управления временем жизни можно использовать: ручное, подсчёт ссылок, сборку мусора, множество гибридных схем и т.д.
Наибольшее приемущество С++ тут в том, что схемы можно выбирать и комбинировать, и даже применять разные схемы для разных объектов. Причём всё не так страшно, как кажется на первый взгляд. Например вполне можно представить систему, где:
— для маленьких объектов, которые выделяются в большом кол-ве, используется аллокатор для объектов фиксированного размера
— для объектов, для которых время жизни чётко ограничено определенной областью, регион-аллокатор
— для аллокации все остальных объектов используется хип
для управления временем жизни используется:
— регион-аллокатор (он же разновидность ручного управления памяти)
— для остальных подсчёт ссылок
Как следствие второй момент. В общем случае ничего не обязательно — не обязательно делать "interlockedincrement/decrement", не обязательно делать "stop the world".
Например смотри схему управления памятю без "interlockedincrement/decrement": http://www.rsdn.ru/forum/message/2605738.1.aspx
Здравствуйте, remark, Вы писали:
R>Да. Не похож. Прострелить ногу и голову одним выстрелом всё ещё можно. R>Помниться сам Boehm как-то говорил, что если Вы хотите его сломать, то не вопрос — у Вас получится Но если если Вы ставите целью его использовать, а не ломать, то он будет работать хорошо, при этом надо понимать что это такое и как работает (последнее в принципе справедливо и для "GC из C#/Java", хотя наверное в меньшей степени).
Проблема в том, что разработчик, выделяя буфер для шифрования или массив для перемножения матриц, даже не будет задумываться о том, что это может повлиять на GC.
А другая сторона медали в том, что я могу написать библиотеку, использующую внутри вещественную арифметику. А кто-то возьмется ее использовать совместно с консервативным GC даже не зная, что у меня внутри матрицы перемножаются. И временами у его программы будет крышу яносить, а найти причины этому вообще вряд ли удастся.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>>Я подумал, что в них применялся GC NBN>Я этого не говорил.
Тогда давай так: тебе лично удавалось писать C++ный программы с GC?
E>>У меня есть масса C++ного кода, который работает и использует сериализацию C++ классов. Что ни в коем случае не доказывает наличия сериализации в C++. NBN>Ну сейчас буст включат в стандарт и будет тебе сериализация в С++.
Не нужно подменять тему разговора. В существующем стандарте C++ нет ни сериализации, ни GC.
E>>Следуя определенным правилам можно написать программу на языке C++, которая будет работать под GC. Но это будет конкретная программа, а вовсе не факт того, что в C++ появился GC. NBN>Налицо явное нарушение логики...
Если не обращать внимания на "следуя определенным правилам" -- то нарушение. Но ее игнорирование так же является нарушением логики.
E>>Если по твоим же словам с STL он не дружит, значит его и нет. NBN>Не значит.
Не, просто проект нужно делать в нетрадиционном для С++ стиле. А учитывая, что некоторых личностей не уговорить использовать даже SP... Определённые оговорки по использованию GC всётаки есть. Ну и STL не приспособлен к GC
Вопрос простой: совместим ли C++ный STL с GC в C++?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>А другая сторона медали в том, что я могу написать библиотеку, использующую внутри вещественную арифметику. А кто-то возьмется ее использовать совместно с консервативным GC даже не зная, что у меня внутри матрицы перемножаются. И временами у его программы будет крышу яносить, а найти причины этому вообще вряд ли удастся.
Сильно сносить не будет. А вообще — думаю, что gc под С++ получит значительно большее распространение с выходом стандарта.
Здравствуйте, eao197, Вы писали:
E>Тогда давай так: тебе лично удавалось писать C++ный программы с GC?
Нет, я только проверял его работоспособность на разного рода тестах. Лично мне gc не нужен, ни в одном из проектов. Специфика не та.
NBN>>Ну сейчас буст включат в стандарт и будет тебе сериализация в С++. E>Не нужно подменять тему разговора. В существующем стандарте C++ нет ни сериализации, ни GC.
Ну и что??? Гуйни там тоже нет, но это не мешает писать гуйню на С++.
E>>>Следуя определенным правилам можно написать программу на языке C++, которая будет работать под GC. Но это будет конкретная программа, а вовсе не факт того, что в C++ появился GC. NBN>>Налицо явное нарушение логики... E>Если не обращать внимания на "следуя определенным правилам" -- то нарушение. Но ее игнорирование так же является нарушением логики.
Следуя определенным правилам можно написать программу на языке C++, которая будет работать с использованием SP. Но это будет конкретная программа, а вовсе не факт того, что в C++ появился SP.
Аналогия ясна?
E>Вопрос простой: совместим ли C++ный STL с GC в C++?
При определённой реализации GC — определённо совместимы. В общем же случае — надо думать.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Да. Не похож. Прострелить ногу и голову одним выстрелом всё ещё можно. R>>Помниться сам Boehm как-то говорил, что если Вы хотите его сломать, то не вопрос — у Вас получится Но если если Вы ставите целью его использовать, а не ломать, то он будет работать хорошо, при этом надо понимать что это такое и как работает (последнее в принципе справедливо и для "GC из C#/Java", хотя наверное в меньшей степени).
E>Проблема в том, что разработчик, выделяя буфер для шифрования или массив для перемножения матриц, даже не будет задумываться о том, что это может повлиять на GC.
E>А другая сторона медали в том, что я могу написать библиотеку, использующую внутри вещественную арифметику. А кто-то возьмется ее использовать совместно с консервативным GC даже не зная, что у меня внутри матрицы перемножаются. И временами у его программы будет крышу яносить, а найти причины этому вообще вряд ли удастся.
Если ты хочешь дружить с Boehm GC, а не воевать, то всё будет работать хорошо.
Во-первых, он не рассматривает объекты, выделенные с помощью других аллокаторов (malloc, new, VirtualAlloc) — не управляет их временем жизни и не ищет в них указатели. Т.е. выделять надо с помощью специального GC_MALLOC. Т.е. сторонняя библиотека, выделевшая матрицу, отпадает.
Далее можно выделить "плоский" блок данных, в котором GC не будет искать указатели (для матриц, строк, массивов и т.д.) — GC_MALLOC_ATOMIC.
Далее можно выделить блок памяти, которым GC не будет управлять, но тем не менее будет искать в нём ссылки — GC_MALLOC_UNCOLLECTABLE.
Далее можно выделить блок памяти, который должен "держаться" указателями на своё начало (на первые 512 байт) — GC_MALLOC_IGNORE_OFF_PAGE. Допустим есть огроменный объект, и допустим ты держишь указатель на его начало, пока используешь его. В таком случае GC "соберёт" его если нет указателей на первые 512 его байт, даже если есть некий double прикинувшийся указателем на 513 байт этого объекта.
Естественно, это всё надо знать и учитывать. Ествественно, надо прочитать описание интерфейса и доступные функции, перед тем, как использовать в проекте. И т.д. Но в целом это — работающий GC для C++.