Re[4]: Visual C# vs C++. Надо сравнить перспективы.
От: Evgeny.Panasyuk Россия  
Дата: 28.12.16 02:00
Оценка: 22 (3) +2
Здравствуйте, 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 немного другая семантика, но при необходимости можно сделать клон с такой же семантикой.
Отредактировано 28.12.2016 2:23 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 28.12.2016 2:03 Evgeny.Panasyuk . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.