Вместо ref A можешь поставить A * или gc_ptr<A>. Полегчало?
твоя ошибка в том, что ты ищешь в C++ то, чего там никогда не было, и не будет.
А именно, неких жёстко прибитых гвоздями к ЯП «ref», которые всю маркировку для GC делают за тебя так, как им это удобно.
Да, я согласен с тем, что юзер класса не должен иметь доступа к реализации ref, но идеология C++ в том и состоит, что ты должен придумать свои ref, или взять готовые, которые кто-то придумал. А в самом ЯП их НЕТ.
Какие шаблоны? Ты сказал, что я могу вставить метаинформацию. Я тебя и спрашиваю, как ее вставить? Вот мне нужно для класса A вставить информацию о полях-ссылках в экземпляре(их смещение и тип). Как?
а у меня отдельный модуль, который НЕ является частью C++.
Вам с emulek, прежде чем утверждать, что в С++ можно сделать полноценный GC, неплохо бы было изучить, что собственно GC из себя представляет.
по твоим словам сразу понятно, что ты не знаком с трудами Кнута, и с прочими работами по теории GC. Но за то видел чью-то реализацию, правда только снаружи. Вот потому-то она для тебя и такая магическая.
На самом деле, никакой магии в алгоритмах GC нет. И они легко реализуются на любом Тьюринг-полном ЯП. Вот только в той же сишечке они совершенно неюзабельны, ибо там для любого нестандартного типа, кроме void*, ничего и нет. Но вот в C++ — всё необходимое имеется. И типы, и инкапсуляция.
Ты же, вместо создания своего типа, пытаешься использовать имеющиеся указатели, и плачешь, что у них «недостаточно возможностей». Да, недостаточно. А что ты хотел от указателя, у которого всего ДВЕ возможности:
1. указатель умеет хранить адрес объекта.
2. к указателю жёстко прибит размер объекта.
Естественно, указатель сам по себе НЕ может быть использован для GC, ибо в указателе просто НЕГДЕ хранить какую-то другую информацию.
по твоим словам сразу понятно, что ты не знаком с трудами Кнута, и с прочими работами по теории GC. Но за то видел чью-то реализацию, правда только снаружи. Вот потому-то она для тебя и такая магическая.
Я знаком с реально используемыми алгоритмами и их реализациями в различных средах и языках. Никакой магии. Во времена Кнута не было ни поколений, ни перемещений. А мы именно о таких развитых сборщиках и говорим. Ты утверждаешь, что можно сделать их на С++. Я же говорю, что это возможно только на уровне рантайма, но не на уровне библиотек. Т.е. на С++ можно написать сборщик, например, для другого языка. Или даже для С++, но с расширениями языковыми. Но сделать полноценный сборщик для С++ в виде библиотеки невозможно.
Ты же, вместо создания своего типа, пытаешься использовать имеющиеся указатели, и плачешь, что у них «недостаточно возможностей».
Я ничего не говорил именно про имеющиеся указатели. Пусть будет отдельный тип указателей. Все-равно не сможешь.
Я знаком с реально используемыми алгоритмами и их реализациями в различных средах и языках. Никакой магии. Во времена Кнута не было ни поколений, ни перемещений.
перемещения были. А про поколения я точно не помню...
А мы именно о таких развитых сборщиках и говорим. Ты утверждаешь, что можно сделать их на С++. Я же говорю, что это возможно только на уровне рантайма, но не на уровне библиотек. Т.е. на С++ можно написать сборщик, например, для другого языка. Или даже для С++, но с расширениями языковыми. Но сделать полноценный сборщик для С++ в виде библиотеки невозможно.
можно, но только в пределах данных определённого класса.
Т.е. можно сделать class array, который будет совершенно аналогичен array из php (разница будет только в синтаксических деталях). Т.е. GC будет работать для этих array точно также.
Только не путай пожалуйста мой класс array, с шаблоном std::vector.
Я ничего не говорил именно про имеющиеся указатели. Пусть будет отдельный тип указателей. Все-равно не сможешь.
ок. ЧЕГО именно я не смогу? Повторять ПОЛНОСТЬЮ реализацию array из php мне вправду лениво.
Анонимус, рассуждающий о достоинствах/недостатках С++, при этом путающий базовый синтаксис плюсов c синтаксисом D (или чем там).
Рукалицо. Так что вот этим:
Вместо ref A можешь поставить
я заниматься не стану, мне и без этого уже всё ясно.
да предубеждённость у него, у человека испорченого сишечкой и крестами в придачу. как будто, то что
C++ и C# — это самые развитые ЯП, по количеству фич на уровне синтаксиса опережающие все остальные языки.
это что-то хорошее.
нафига вообще нужно «большое количество фич на уровне синтаксиса»? вам что, сахарку не хватает? нужно не много, нужно достаточно.
просто человек с позиций «ассемблера высокого уровня» воспринимает сишечку и кресты по инерции как что-то близкое, родное, хоть оно и уродство с костылями, но уродство знакомое, понятное. и фичами первого порядка считает статическую типизацию, всякие полоумные указатели, второго порядка — алгоритмы и императивщину, третьего порядка — какую-то сборную солянку, как это принято в плюсах, из объектов, шаблонов и C++11х впридачу. и плевать что эти фичи в цельную систему не складываются (например, вместо рассуждения как использовать совместо эти 2-3 фичи в системе — нубские рассуждения какая фича важней другой, типа слон кита зарулит ли)
человек с позиций лиспа и символьных вычислений, например, думает по-другому. здесь есть символы, и их значения в контексте других вычислений. и между ними ad hoc строится какой-то алгоритм, то есть алгоритм является сущностью более последнего порядка по сравнению с символами, символьными вычислениями (частный случай — объектами), и языком вычисления символов (на макросах, например). то есть, фича первого порядка — символы и списки свойств символов, второго — гомоиконность и реализация макросов, третьего — рефлексия конпелятора, что позволяет не вводить отдельные фичи 4-5-10500 порядка, отдельно в ядро языка, а реализовывать их через фичи 1-2-3
человек в каком-нибудь хаскеле ну или factor вообще смотрит на мир как камбала, с другой особой точки зрения, со своими особыми ламповыми комбинаторами.
**
и фишка в том, что все эти фичи важны, но по своему, со своей точки зрения. все они позволяют добиться по сути одного и того же (ну где-то чуть более мощнее, где-то чуть менее), но «свои» фичи ближе к телу и понятнее, и типа важнее.
так вот, фигня это всё. важна совокупность свойств, система как единое целое. хороший программист отличается от плохого только тем, что он умеет решать задачи быстро и качественно (а плохой, соответственно — не умеет), а не тем, какого цвета у него раскраска в редакторе, какое IDE, систему сборки и VCS он использует, какие на вкус батарейки если полизать в этом языке, или как называется языка конпелятор.
не так важен язык, не так важны фичи, как важна способность строить систему решающую задачу из всего этого. а способы строить в разных языках общеприняты бывают разные, и дело не в том что одна школа кунгфу более канонiчна одна фича важнее другой, а в техничности, которая отличает одепта от мастера способности их применять совместно.
Хорошо. Я с твоего позволения не буду городить умный указатель сам, а просто воспользуюсь std::shared_ptr из нового стандарта, который в полной мере реализует вышеозначенный алгоритм.
Как видишь, никакой магии. Я просто создал два объекта содержащие умные указатели друг на друга. Это вполне рядовая ситуация для кольцевых буферов, иерархий виджетов, моделей данных нетривиальных программ типа компьютерных игр, IDE, фотошопов etc. Как ты думаешь сколько раз будет вызван деструктор?
ВАЖНО: это ОДНА ИЗ реализаций и она НЕ РАБОТАЕТ. Давай ДРУГУЮ.
Есть еще один случай, когда удобен C/C++. Это тот случай, когда в вебе надо реализовать логику, которая уже реализована на C/C++.
сходу могу придумать ещё один случай. например, был под дельфи сервер приложений Байконур, который был устроен почти аналогично формочкам с кнопачками, то есть просто в приложении с GUI заменяли стандартные компоненты на байконуровские — и получался сервер приложений мордой в веб.
Я просто создал два объекта содержащие умные указатели друг на друга. Это вполне рядовая ситуация для кольцевых буферов, иерархий виджетов, моделей данных нетривиальных программ типа компьютерных игр, IDE, фотошопов etc.
Справедливости ради стоит сказать, что в С++ в данном случае скорее всего будет просто std::list.
Этот список необходим для работы сборщика мусора. Без него он банально не может определить какие объекты надо собирать, а какие — нет.
можно и без списка. например, как тайптеги в лиспах: сделать бит-предикат что собирать не надо (в ephemeral GC и так тайптеги используются только для проверки на то, объект ли это в хипе или простое значение какого-то типа, ну сделать к нему аналогичный бит-предикат объект в стеке, foreign объект, который собирать не надо). только всё равно эти битхаки как-то надо будет вычислять, во время компиляции каждой отдельной функции.
заведи например, битовую карту «GC проверяет объект», и нарисуй своё тёплое ламповое соглашение о вызовах через asm naked.
и вообще, с анализом регионов как-то GC красивей чем с тайптегами получается.
это невозможно. полноценному сборщику нужна метаинформация, карта ссылок объекта, карта рутовых объектов. в jvm и clr этим занимаются компилятор и jit.
невозможно в С++ или вообще в CTFE? а то мимимишная девочка написала на D занятный JIT с GC для JavaScript, активно пользуется там CTFE во все поля.
Да кто бы спорил. Кольцевые буферы прекрасно реализуются поверх вектора или списка, виджеты в иерархии вложены и порядок их освобождения самоочевиден. А вот в моделях данных такая петрушка иногда имеет место быть, причём довольно запутанная. Я не против если кто-то придумает более осмысленный и вместе с тем короткий код где уместны кольцевые ссылки и неоднозначный порядок освобождения ресурсов.
а то мимимишная девочка написала на D занятный JIT с GC для JavaScript, активно пользуется там CTFE во все поля.
Для стороннего языка JIT и GC можно наверное при большом желании написать и на bash'е (это будет неторопливый JIT). Вопрос именно в расширении самого языка сборкой мусора без модификации компилятора.
type traits можно изобразить на шаблонах (тот же буст), хоть и более коряво чем в D
отсутствие карты полей-ссылок объекта.
вопрос, можно ли её построить в ограниченном С++-шном CTFE шаблонами. в D, с более нормальным CTFE, есть ощущение что можно.
Ты не сможешь корректно запомнить карту для функции(например), т.к. при следующем исполнении данной функции, карта может быть совсем другой и ты не можешь это определить, для этого тебе придется интерпретировать машкод.
можно без интерптетации: изобразить свой calling convention с дополнительной битовой картой, а карту строить каким-то конечным автоматом типа predicate dispatch. и диспетчить по предикатам в разные thunks.
автомат считать в CTFE.
вопрос, сработает ли это в ограниченном С++-шном CTFE.
The reason C++ doesn’t have garbage collection is not because it can’t be done in an efficient way, but because C++ itself is hostile to GC. The compiler and the runtime have to always assume the worst — not only that any pointer can alias any other pointer but that a memory address can be stored as an integer or its lower bits could be used as bitfields (that’s why only conservative garbage collectors are considered for C++).
12 Memory Manager
The Corman Lisp Memory Manager consists of several functions to allocate
memory, and the garbage collector. None of these functions are designed to be called
explicitly. Instead, memory management code is called implicitly when you call
Common Lisp functions.
Corman Lisp includes a state-of-the-art garbage collector for efficient use of
memory. It is designed for maximum performance, no noticeable pauses, and good
virtual memory behavior. Technically the Corman Lisp garbage collector (which is
implemented in the kernel) has the following attributes:
• Copying (live data is moved during collection)
• Generational (there are several generations of heap objects sorted by age)
• Compacting (the collection process results in a compact heap with no
fragmentation)
• Virtual-memory friendly (it works with the virtual memory system)
These attributes have been shown to be especially good for Common Lisp
implementations. There are several implications of this, some positive, and some
negative.
Memory allocation is extremely fast. It is nearly as fast as stack allocation. Since
fragmentation is not an issue, the memory manager need only increment a pointer
into free space to allocate a block of arbitrary size.
Garbage collection normally only collects Generation 0 data, and copies live data
into Generation 1. This operation takes just a few milliseconds. When Generation 1
fills up, it causes live data from Generation 1 to be copied into Generation 2. The
virtual memory hardware is used to detect when older generation heap objects have
been modified to point to younger generation heap objects, thus avoiding the
overhead of keeping track of that in software.
ну не то чтобы совсем без. обмазавшись шаблонами со SFINAE, например бустом можно что-то придумать с type traits. можно вообще ORM написать во время CTFE как здесь, в GOODS — его диссер.ps.gz (автореферат).
ещё похожий по принципам код есть у него на странице (например, здесь «Reflection Package for C++»)
в диссере он по сути пишет OODB через ORM на шаблонах С++ с рефлексией времени компиляции.
похожим принципом можно.
вопрос в том, достаточно ли такой метаинформации, или в С++ с его убогим CTFE ничего не поделаешь (из-за убогой поддержки в рантайме, например).
Я могу это написать для рантайма, но я не могу заставить С++ записывать эту информацию. Мне придется определять и использовать кучу макросов. Я никак в С++ не могу сделать так, чтобы
напиши в первом приближении плагин для clang-а который будет эту метаинформацию записывать в аннотации LLVM. а вот можно ли её воткнуть в C++ шаблоны — это особая уличная магия.
BlackBox Component Pascal — mark&sweep на паскале; Nimrod — GC на Nimrod, HLVM
Не очень удачные примеры. Все эти языки планировались управляемыми. C++ проектировался языком с ручным управлением памяти. Приведи пример языка без сборщика мусора в который этот сборщик мусора можно добавить как библиотеку (а не выключить оный как D).
Так дело-то не в том, можно ли написать реализацию GC на том или ином языка, а в том, можно ли использовать GC в том или ином языке, если сам язык GC не поддерживает.
Такому классу не нужен GC, он будет владеть памятью и удалит ее в деструкторе.
это потребует времени и приведёт к фрагментации памяти. Он может НЕ отдавать память. Это как уборщица, которая убирает мусор только вечером. А не весь день за каждой соринкой бегает и под ногами путается у работников.
а просто воспользуюсь std::shared_ptr из нового стандарта, который в полной мере реализует вышеозначенный алгоритм.
не катит.
Я просто создал два объекта содержащие умные указатели друг на друга. Это вполне рядовая ситуация для кольцевых буферов, иерархий виджетов, моделей данных нетривиальных программ типа компьютерных игр, IDE, фотошопов etc.
я понимаю, что гвоздь — вполне рядовое крепление. А при чём тут отвёртка?