Здравствуйте, bazis1, Вы писали:
B>>>* Нет нормального garbage collector-а.
EP>>Есть консервативные сборщики мусора, причём им не первый десяток лет, но их никто не использует, потому что нет такой необходимости.
B>Ими никто не пользуется, потому что из вот такого объявления:
B>B>class Inner : public ManagedObject<Inner> ...
B>
B>нельзя получить вот такой граф, без которого никакой сборщик мусора никогда не разрулит ни одну круговую зависимость:
B>B>+--------+ m_pInner +-------+
B>| pOuter | -----------> + Inner +
B>+--------+ +-------+
B>
B>Это можно сделать через макросы и специальные конструкторы, но это усложнит задачу до уровня непрактичности.
Консервативные сборщики мусора это всё разруливают, для этого не нужны никакие макросы и прочие "ManagedObject" (они нужны для
точных библиотечных GC).
Смотри например Boehm GC.
EP>>Нужно держать и что-то там разруливать в исключительных случаях, а никак не постоянно.
B>Если это не делать постоянно, то потом будете полдня отлавливать memory leaks в дебаггере.
Во-первых GC не спасает от утечек. Во-вторых утечка памяти это минорная проблема, особенно по сравнению с утечкой ресурсов (которую на C# получить проще).
В-третьих, вот пример кода:
auto calculate_something(...)
{
vector<Values> xs;
fill(xs);
for(auto &x : xs)
calc(x);
// ...
return xs;
}
Здесь никакого ref-counting и прочего, все значения имеют простой life-time привязанный к scopes — как и >90% всех объектов в программе.
В некоторых случаях да, нужны unique_ptr, ещё в более редких shared_ptr, ещё реже нужен weak_ptr — но это не означает что на каждый new в C# программе в аналоге на C++ будут *_ptr и прочие заморочки.
EP>>99% случаев разруливаются scope-based lifetime, даже без всяких *_ptr и прочего ref-counting.
B>Ага, реализуйте мне MVC GUI без reference-counting.
GUI обычно не является какой-то огромной частью кода C++, более того для формочко-ориентированной разработки я именно C# и советовал в соседнем сообщении.
B>>>и таких примеров много. Соответственно, одинаковый по функционалу код получается более громоздким и дорогим в поддержке.
EP>>Это типа 4k строк нагенерированных на ровном месте?
B>Ничего не понял. Вы дали ссылку на какую-то левую библиотеку с непонятным нагенерированным кодом, который очень похож на то, что делает Linq. Что это должно означать, что на C++ не написано тонн подобных библиотек?
Для C++ в этом случае не нужна никакая генерация кода, в этом
реальном примере именно C# показывает свою громоздкость и дорогую поддержку (текстовую кодогенерацию поддерживать сложнее).
B>>>* Нет yield return, async/await,
EP>>Во-первых есть библиотечные (например на базе Boost.Coroutine). А во-вторых если речь про MSVS — то там начиная с ЕМНИП 2015 есть встроенное расширение.
B>Вопрос в том, насколько лаконично они выглядят. Давайте, что ли, пример, аналогичный вот этому:
B>B>IEnumerable<int> MakeSquares(int max)
B>{
B> for (int i = 0; i < max; i++)
B> yield return i * i;
B>}
B>...
B>foreach(var s in MakeSquares(10))
B>{
B> if (s > 10)
B> break;
B>}
B>
auto make_squares(int max)
{
return coroutine<int>::pull_type{[=](auto &yield)
{
for (int i = 0; i < max; i++)
yield(i * i);
}};
}
...
for(auto x : make_squares(10))
{
if(x > 10) break;
cout << x << endl;
}
Вот
Live Demo. Причём yield здесь не ограничен лишь одним уровнем как yield return, и может быть вызван на произвольно-глубоком уровне callstack'а, даже сквозь сторонний код который об этом yield ничего не знает.
B>>>LINQ
EP>>Для in-memory последовательностей есть Boost.Range. А для взаимодействия с DB есть как отдельные библиотеки с декларативным описанием запросов, так и целые системы а-ля ODB.
B>Я не про ДБ, а про упрощение работы с данными. Что-то вроде такого:
B>B>var surnamesByFrequency = fullNames
B> .GroupBy(fn => fn.Surname)
B> .Select(pair => new {Surname = pair.First, Count = pair.Second.Unique().Count()})
B> .OrderBy(rec => rec.Count);
B>
B>Т.е. берем массив структур "имя, фамилия", группируем по фамилиям, потом считаем количество уникальных имен для каждой фамилии, потом сортируем и получаем массив объявленных на ходу структур.
B>На плюсах будет раз в пять больше кода.
Я же говорю, в случае не-БД ближайшем аналогом будет библиотека Range, примерно так:
auto surnames_by_frequency = full_names
| group_by(PROJ(surname))
| view::transform([](const auto &ys)
{
return NEW( (surname, first(ys).surname) (count, distance(ys | view::unique)) );
})
| order_by(PROJ(count));
for(auto x : surnames_by_frequency)
cout << x.surname << " " << x.count << endl;
"Примерно" потому что у group_by и unique из Range немного другая семантика, но при необходимости можно сделать клон с такой же семантикой.