Re[16]: Ой, чо с D деется-то!?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 25.10.07 14:33
Оценка:
Здравствуйте, VladD2, Вы писали:

E>>http://en.wikipedia.org/wiki/Visual_C%2B%2B#History

E>>

E>>Visual C++ 1.0, which included MFC 2.0, was the first version of Visual C++, released in 1992, available in both 16-bit and 32-bit versions.


E>>Кстати, изначально C++ использовался на Unix-ах и самые продвинутые компиляторы C++ были вовсе не на PC, а на Unix-овых рабочих станциях.


VD>Вот теперь подумай, исходя из этих данных, когда С++ рельно был в пике слав (испытал триумф). Это в лучшем случае 1995-ый, а то и 1998-ой.


С середины 90-х в мире начался медленный закат C++ -- его начали вытеснять такие языки, как Visual Basic и Java, а в дальнейшем и C#.

В 95-м Sun во всю пропагандировал Java как "правильно сделанный C++". Если бы C++ не был бы тогда на пике славы (как ты выражаешься), вряд ли стал противопоставлять Java какому-то там C++у.

Да и то, что вечно опаздывающая со стартом MS в 92-м выпустила C++ный компилятор говорит само за себя.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: Ой, чо с D деется-то!?
От: c-smile Канада http://terrainformatica.com
Дата: 26.10.07 02:12
Оценка: :))
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, c-smile, Вы писали:


CS>>Я ему лично это и говорил. И не раз.


A>И что он ответил?


Он было уже уговорился но тут подкатил тезка по фамилии Александреску и почалась сеча по новой...
Re[7]: try-finally и scope(exit)
От: Пётр Седов Россия  
Дата: 26.10.07 13:26
Оценка:
Здравствуйте, eao197, Вы писали:
E>Вообще-то RAII на scope-классах в D делают все это еще компактнее и удобнее.
Если классы одноразовые, то не компактнее и не удобнее. Я не люблю захламлять программу одноразовыми мелкими классами-обёртками. Сравните:
// RAII подход

class ResA // используется только в функции Func_RAII
{
  Handle m_Handle;

  this(...)
  {
    m_Handle = AllocResA(...);
  }

  ~this()
  {
    FreeResA(m_Handle);
  }
}

class ResB // используется только в функции Func_RAII
{
  Handle m_Handle;

  this(...)
  {
    m_Handle = AllocResB(...);
  }

  ~this()
  {
    FreeResB(m_Handle);
  }
}

class ResC // используется только в функции Func_RAII
{
  Handle m_Handle;

  this(...)
  {
    m_Handle = AllocResC(...);
  }

  ~this()
  {
    FreeResC(m_Handle);
  }
}

void Func_RAII(...)
{
  scope A = new ResA(...);
  scope B = new ResB(...);
  scope C = new ResC(...);
  // использовать ресурсы A, B, C
  ...
}

и:
// scope(exit) подход

void Func_ScopeExit(...)
{
  Handle hResA = AllocResA(...);
  scope(exit) FreeResA(hResA);

  Handle hResB = AllocResB(...);
  scope(exit) FreeResB(hResB);

  Handle hResC = AllocResC(...);
  scope(exit) FreeResC(hResC);

  // использовать ресурсы A, B, C
  ...
}

Bright пишет в статье «Exception Safe Programming»:

The RAII solution often requires the creation of an extra dummy class, which is both a lot of lines of code to write and a lot of clutter obscuring the control flow logic. This is worthwhile to manage resources that must be cleaned up and that appear more than once in a program, but it is clutter when it only needs to be done once.

The RAII approach involves the creation of dummy classes, and the obtuseness of moving some of the logic out of the abc() function.

Иногда RAII смотрится искусственно. Например, как назвать RAII-класс в следующих случаях?
glPushMatrix();
try
{
  glTranslated(...);
  glRotated(...);
  ...
}
finally
{
  glPopMatrix();
}

ListBox.DisableRepaint(); // WM_SETREDRAW wParam = FALSE
try
{
  for (100 раз)
  {
    ListBox.AddItem(...);
  }
}
finally
{
  ListBox.EnableRepaint(); // WM_SETREDRAW wParam = TRUE
}
Пётр Седов (ушёл с RSDN)
Re[8]: try-finally и scope(exit)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 26.10.07 13:48
Оценка: +1
Здравствуйте, Пётр Седов, Вы писали:

ПС>Здравствуйте, eao197, Вы писали:

E>>Вообще-то RAII на scope-классах в D делают все это еще компактнее и удобнее.
ПС>Если классы одноразовые, то не компактнее и не удобнее. Я не люблю захламлять программу одноразовыми мелкими классами-обёртками.

Ну дык если одноразовые, тогда может быть. Редко, правда, встречаются такие одноразовые.

Однако

ПС>Сравните:

ПС>
ПС>void Func_RAII(...)
ПС>{
ПС>  scope A = new ResA(...);
ПС>  scope B = new ResB(...);
ПС>  scope C = new ResC(...);
ПС>  // использовать ресурсы A, B, C
ПС>  ...
ПС>}
ПС>

ПС>и:
ПС>
ПС>// scope(exit) подход

ПС>void Func_ScopeExit(...)
ПС>{
ПС>  Handle hResA = AllocResA(...);
ПС>  scope(exit) FreeResA(hResA);

ПС>  Handle hResB = AllocResB(...);
ПС>  scope(exit) FreeResB(hResB);

ПС>  Handle hResC = AllocResC(...);
ПС>  scope(exit) FreeResC(hResC);

ПС>  // использовать ресурсы A, B, C
ПС>  ...
ПС>}
ПС>


Первую форму (со scope-классами) я предпочту второй. Поскольку в первой логика Func не захломляется низкоуровневыми деталями захвата/освобождения ресурсов. Сколько дополнительных определений нужно для Func -- это второй вопрос, он менее важен, чем компактность и прозрачность самой Func.

ПС>Иногда RAII смотрится искусственно. Например, как назвать RAII-класс в следующих случаях?

ПС>
ПС>glPushMatrix();
ПС>try
ПС>{
ПС>  glTranslated(...);
ПС>  glRotated(...);
ПС>  ...
ПС>}
ПС>finally
ПС>{
ПС>  glPopMatrix();
ПС>}
ПС>

ПС>
ПС>ListBox.DisableRepaint(); // WM_SETREDRAW wParam = FALSE
ПС>try
ПС>{
ПС>  for (100 раз)
ПС>  {
ПС>    ListBox.AddItem(...);
ПС>  }
ПС>}
ПС>finally
ПС>{
ПС>  ListBox.EnableRepaint(); // WM_SETREDRAW wParam = TRUE
ПС>}
ПС>


Это может решаться совсем другим способом, благо в D есть для этого соответствующие средства:
void soSomethingWithGl()
  {
    void pushAndDo( lazy void block ) {
      glPushMatrix();
      try { block; }
      finaly { glPopMatrix(); }
    }

    pushAndDo( {
      glTranslated(...);
      glRotated(...);
    } );
  }


Со временем, такие вот методы pushAndDo будут образовывать целые модули вспомогательных функций для повторного использования. И scope-классы здесь, опять же, смогут работать не менее успешно.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: try-finally и scope(exit)
От: Пётр Седов Россия  
Дата: 26.10.07 16:52
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Извиняюсь, но функциональный эквивалент вышесказанного есть следующее:

CS>…
CS>Что несколько многословнее но gets job done.
А что если ресурсы иерархические? Сравните:
void Func_TryFinally(...)
{
  Handle hResA = AllocResA(...);
  try
  {
    int CountA = GetCountA(hResA);
    for (int IndexA = 0; IndexA < CountA; IndexA++)
    {
      Handle hResB = AllocResB(... hResA ... IndexA ...);
      try
      {
        int CountB = GetCountB(hResB);
        for (int IndexB = 0; IndexB < CountB; IndexB++)
        {
          Handle hResC = AllocResC(... hResB ... IndexB ...);
          try
          {
            // использовать ресурс C
            ...
          }
          finally
          {
            FreeResC(hResC);
          }
        }
      }
      finally
      {
        FreeResB(hResB);
      }
    }
  }
  finally
  {
    FreeResA(hResA);
  }
}

и:
void Func_ScopeExit(...)
{
  Handle hResA = AllocResA(...);
  scope(exit) FreeResA(hResA);
  int CountA = GetCountA(hResA);
  for (int IndexA = 0; IndexA < CountA; IndexA++)
  {
    Handle hResB = AllocResB(... hResA ... IndexA ...);
    scope(exit) FreeResB(hResB);
    int CountB = GetCountB(hResB);
    for (int IndexB = 0; IndexB < CountB; IndexB++)
    {
      Handle hResC = AllocResC(... hResB ... IndexB ...);
      scope(exit) FreeResC(hResC);
      // использовать ресурс C
      ...
    }
  }
}

Такой код вполне может возникнуть при работе с каким-нибудь MSXML.

CS>Во вторых как сказал Сальватор Eao есть еще фенечка по имени auto (та которая stack based instance) — RAII и все такое.

Имеется в виду eao197? Я ему уже ответил — RAII не всегда удобен, иногда scope(exit) удобнее (по-моему).

CS>Ну давай еще добавим on error resume next из VB, тоже в общем-то элегантное решение.

С этой штукой не знаком .

CS>Я к тому что можно до чертиков чего напридумать но зачем лепить перекрывающиеся механизмы?

Эти механизмы технически эквивалентны, но идейно различаются:
* RAII — для многоразовых ресурсов.
* scope(exit) — для одноразовых ресурсов.
* try-finally — для временной смены состояния (например, glPushMatrix/glPopMatrix).
По-моему, все три механизма имеют право на жизнь. Кстати, Bright считает try-finally избыточным. В статье «Exception Safe Programming» он пишет:

When to use RAII, try-catch-finally, and Scope
RAII is for managing resources, which is different from managing state or transactions. try-catch is still needed, as scope doesn't catch exceptions. It's try-finally that becomes redundant.

Пётр Седов (ушёл с RSDN)
Re[8]: try-finally и scope(exit)
От: c-smile Канада http://terrainformatica.com
Дата: 26.10.07 21:03
Оценка: 12 (2) +2
Здравствуйте, Пётр Седов, Вы писали:

CS>>Извиняюсь, но функциональный эквивалент вышесказанного есть следующее:

CS>>…
CS>>Что несколько многословнее но gets job done.
ПС>А что если ресурсы иерархические? Сравните:

Я просто показал что приведенный тобой код для finally и scope() не эквивалентен.

ПС>Такой код вполне может возникнуть при работе с каким-нибудь MSXML.


У MSXML каждый node это refcounted object. В D (как и в любом другом GC environment) .
для работы с ним нужно нечто типа smart pointer т.е. RAII. Любой другой способ включая
scope(exit) это источник ошибок.

CS>>Во вторых как сказал Сальватор Eao есть еще фенечка по имени auto (та которая stack based instance) — RAII и все такое.

ПС>Имеется в виду eao197? Я ему уже ответил — RAII не всегда удобен, иногда scope(exit) удобнее (по-моему).

scope(exit) сделан Вальтером в ответ на претензии о том что для stack based struct нет ctor/dtor.
Т.е. это паллиатив а не решение. stack based объекты в C++ это мощная концепция и scope(exit) решает проблему только частично.


CS>>Ну давай еще добавим on error resume next из VB, тоже в общем-то элегантное решение.

ПС>С этой штукой не знаком .

CS>>Я к тому что можно до чертиков чего напридумать но зачем лепить перекрывающиеся механизмы?

ПС>Эти механизмы технически эквивалентны, но идейно различаются:
ПС>* RAII — для многоразовых ресурсов.
ПС>* scope(exit) — для одноразовых ресурсов.
ПС>* try-finally — для временной смены состояния (например, glPushMatrix/glPopMatrix).
ПС>По-моему, все три механизма имеют право на жизнь. Кстати, Bright считает try-finally избыточным. В статье «Exception Safe Programming» он пишет:
ПС>

ПС>When to use RAII, try-catch-finally, and Scope
ПС>RAII is for managing resources, which is different from managing state or transactions. try-catch is still needed, as scope doesn't catch exceptions. It's try-finally that becomes redundant.


Проблема со scope() состоит в том что scope делает недетерменированным (в о всяком случае явно) последовательность фрагментов
кода которые будут выполняться при выходе из блока.

И опять же если бы у struct были ctor/dtor то scope(exit) не был бы нужен. Соответсвенно и finally не нужен был тоже.
Вальтер всеми ногами упирается в то что struct ctor/dtor это зло и при этом плодит целый фонтан решений которые половинчаты и только засоряют всю картину.
Re[8]: Ой, чо с D деется-то!?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 26.10.07 22:24
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Потом развитие на самом сбее увеличивает мативацию программиста. Он уже сам может оценить насколько новая фича востребована.


Одно но — может так оказаться, что в итоге получится язык для написания компиляторов.
... << RSDN@Home 1.2.0 alpha rev. 725 on Windows Vista 6.0.6000.0>>
AVK Blog
Re[8]: try-finally и scope(exit)
От: alexeiz  
Дата: 27.10.07 10:09
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

ПС>Здравствуйте, eao197, Вы писали:

E>>Вообще-то RAII на scope-классах в D делают все это еще компактнее и удобнее.
ПС>Если классы одноразовые, то не компактнее и не удобнее. Я не люблю захламлять программу одноразовыми мелкими классами-обёртками. Сравните:
...

ПС>Bright пишет в статье «Exception Safe Programming»:

ПС>

ПС>The RAII solution often requires the creation of an extra dummy class, which is both a lot of lines of code to write and a lot of clutter obscuring the control flow logic. This is worthwhile to manage resources that must be cleaned up and that appear more than once in a program, but it is clutter when it only needs to be done once.
ПС>…
ПС>The RAII approach involves the creation of dummy classes, and the obtuseness of moving some of the logic out of the abc() function.


Про ScopeGuard слышал? http://www.ddj.com/cpp/184403758. Walter про него тоже не знал.
Re[9]: try-finally и scope(exit)
От: alexeiz  
Дата: 27.10.07 20:01
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>И опять же если бы у struct были ctor/dtor то scope(exit) не был бы нужен. Соответсвенно и finally не нужен был тоже.

CS>Вальтер всеми ногами упирается в то что struct ctor/dtor это зло и при этом плодит целый фонтан решений которые половинчаты и только засоряют всю картину.

Хм, интересно. Я про это не знал. Где-нибудь про его мотивацию почитать можно? И почему бы не использовать class, у которых есть деструкторы, вместо struct для выполнения соответствующих операций при выходе из scope'а?
Re[10]: try-finally и scope(exit)
От: c-smile Канада http://terrainformatica.com
Дата: 27.10.07 21:29
Оценка: +1
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, c-smile, Вы писали:


CS>>И опять же если бы у struct были ctor/dtor то scope(exit) не был бы нужен. Соответсвенно и finally не нужен был тоже.

CS>>Вальтер всеми ногами упирается в то что struct ctor/dtor это зло и при этом плодит целый фонтан решений которые половинчаты и только засоряют всю картину.

A>Хм, интересно. Я про это не знал. Где-нибудь про его мотивацию почитать можно? И почему бы не использовать class, у которых есть деструкторы, вместо struct для выполнения соответствующих операций при выходе из scope'а?


class wrapper {}
auto wrapper w = new wrapper();


Обрати внимание на new.

в c++ можно перекрывая оператор= сделать managed access к области памяти (shared_ptr например),
в D этого в принципе не сделать.
auto instances это просто еще один способ вызвать процедуру на выходе из блока (dtor). И все.

C++ в этом случае мощнее.
Re[9]: try-finally и scope(exit)
От: Пётр Седов Россия  
Дата: 27.10.07 21:54
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Про ScopeGuard слышал? http://www.ddj.com/cpp/184403758.

ScopeGuard — это слабое подобие D-шных scope(failure) и scope(exit). Например, в конце этой статьи Alexandrescu и Marginean приводят следующий C++-код:

{
    FILE* topSecret = fopen("cia.txt");
    ON_BLOCK_EXIT(std::fclose, topSecret);
    ... use topSecret ...
} // topSecret automagically closed

ON_BLOCK_EXIT says: "I want this action to be performed when the current block exists."

Аналогичный код на D элементарно пишется с помощью scope(exit), без шаблонных выкрутасов и макросов.

A>Walter про него тоже не знал.

Вряд ли. Насколько я знаю, Alexandrescu и Bright тесно общаются и Alexandrescu влияет на D. Также, Bright в конце статьи «Exception Safe Programming» ссылается первым делом на указанную Вами статью:

References:
1. Generic&lt;Programming&gt;: Change the Way You Write Exception-Safe Code Forever by Andrei Alexandrescu and Petru Marginean

Пётр Седов (ушёл с RSDN)
Re[10]: try-finally и scope(exit)
От: VoidEx  
Дата: 27.10.07 23:20
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

ПС>ScopeGuard — это слабое подобие D-шных scope(failure) и scope(exit). Например, в конце этой статьи Alexandrescu и Marginean приводят следующий C++-код:

ПС>

ПС>

ПС>{
ПС>    FILE* topSecret = fopen("cia.txt");
ПС>    ON_BLOCK_EXIT(std::fclose, topSecret);
ПС>    ... use topSecret ...
ПС>} // topSecret automagically closed
ПС>

ПС>ON_BLOCK_EXIT says: "I want this action to be performed when the current block exists."

ПС>Аналогичный код на D элементарно пишется с помощью scope(exit), без шаблонных выкрутасов и макросов.

Эм, данный пример только эквивалентность показывает, а не "слабое подобие".
Re[10]: try-finally и scope(exit)
От: alexeiz  
Дата: 27.10.07 23:12
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

ПС>Здравствуйте, alexeiz, Вы писали:


A>>Про ScopeGuard слышал? http://www.ddj.com/cpp/184403758.

ПС>ScopeGuard — это слабое подобие D-шных scope(failure) и scope(exit). Например, в конце этой статьи Alexandrescu и Marginean приводят следующий C++-код:
ПС>

ПС>

ПС>{
ПС>    FILE* topSecret = fopen("cia.txt");
ПС>    ON_BLOCK_EXIT(std::fclose, topSecret);
ПС>    ... use topSecret ...
ПС>} // topSecret automagically closed
ПС>

ПС>ON_BLOCK_EXIT says: "I want this action to be performed when the current block exists."

ПС>Аналогичный код на D элементарно пишется с помощью scope(exit), без шаблонных выкрутасов и макросов.

Сравни ON_BLOCK_EXIT со своим первоначальным примером. Ты явно упустил из внимания ScopeGuard, когда придумывал аргументы за scope(exit). А теперь ты пытаешься доказать, что такой-же код можно написать на D. Чувствуешь разницу между "смотрите, как D круче: 10 строк C++ кода vs 1 строка D кода" и "на D можно писать код не уступающий C++"?

A>>Walter про него тоже не знал.

ПС>Вряд ли. Насколько я знаю, Alexandrescu и Bright тесно общаются и Alexandrescu влияет на D. Также, Bright в конце статьи «Exception Safe Programming» ссылается первым делом на указанную Вами статью:

Может и не знал, когда он придумывал свой scope(exit), а когда писал статью, уже знал. Но это не так интересно. Настоящая причина введения scope(exit) уже была раскрыта c-smile'ом.
Re[11]: try-finally и scope(exit)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.10.07 08:13
Оценка:
Здравствуйте, c-smile, Вы писали:

A>>Хм, интересно. Я про это не знал. Где-нибудь про его мотивацию почитать можно? И почему бы не использовать class, у которых есть деструкторы, вместо struct для выполнения соответствующих операций при выходе из scope'а?


CS>
CS>class wrapper {}
CS>auto wrapper w = new wrapper();
CS>


CS>Обрати внимание на new.


CS>в c++ можно перекрывая оператор= сделать managed access к области памяти (shared_ptr например),

CS>в D этого в принципе не сделать.
CS>auto instances это просто еще один способ вызвать процедуру на выходе из блока (dtor). И все.

CS>C++ в этом случае мощнее.


Начиная с какой-то версии (незадолго до выхода 1.0) для подобных переменных в D нужно использовать не auto, а scope:
class wrapper {};
scope wrapper w = new wrapper();

Ключевое слово auto используется для автоматического вывода типа переменных, что позволяет писать так:
class wrapper {};
auto scope w = new wrapper();


Но косяк в D со scope классами еще и в том, что если класс задекларирован как scope (т.е. требуется вызывать его деструктор при выходе из области видимости), то объекты этого класса нельзя возвращать из функции:
scope class SomeResourceHolder { ... };

// Так сделать не получится:
SomeResourceHolder lockResource() { ... }
auto resource = lockResource();


В этом плане C++ предлагает более логичные (на мой взгляд) подходы:
class SomeResourceHolder { ... };
typedef std::auto_ptr< SomeResourceHolder > ResourceHolderPtr;

// Так делать в C++ можно без проблем.
ResourceHolderPtr lockResource() { ... }
ResourceHolderPtr resource = lockResource();


Когда в C++0x появится вывод типов -- вообще лепота будет.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Ой, чо с D деется-то!?
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.10.07 15:50
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Одно но — может так оказаться, что в итоге получится язык для написания компиляторов.


Можно хотя бы один пример подобного? И за одно пояснить связть.

А то, я вот знаю С, С++, Паскаль, Лисп... Компиляторы которых писались на сомих себе.
А связи никакой не вижу.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: try-finally и scope(exit)
От: Пётр Седов Россия  
Дата: 29.10.07 22:01
Оценка: 19 (1)
Здравствуйте, VoidEx, Вы писали:
VE>Эм, данный пример только эквивалентность показывает, а не "слабое подобие".
Например, есть D-код:
class View
{
  int m_ItemsLockCount;

  void Paint(bool LockItems)
  {
    if (LockItems) m_ItemsLockCount++;
    scope(exit) if (LockItems) m_ItemsLockCount--;
    // использовать Items
    ...
  }
}

Эквивалентный C++-код с использованием ScopeGuard:
#include "ScopeGuard.h" // ftp://ftp.cuj.com/pub/2000/cujdec2000.zip > alexandr.zip

class View
{
  int m_ItemsLockCount;

  void ConditionallyUnlockItems(bool LockItems) // вызывается динамически
  {
    if (LockItems) m_ItemsLockCount--;
  }

  void Paint(bool LockItems)
  {
    if (LockItems) m_ItemsLockCount++;
    ON_BLOCK_EXIT_OBJ(*this, &View::ConditionallyUnlockItems, LockItems); // здесь ScopeGuard
    // использовать Items
    ...
  }
};

В этом коде мне не нравится две вещи:
* Для маленького кусочка кода приходится городить отдельную функцию-член. Это неудобно.
* Функция-член ConditionallyUnlockItems вызывается динамически (operator.*). Хотя, теоретически, умный оптимизатор может сгенерировать статический вызов, здесь же всё на виду. Если заменить функцию-член на функтор, то можно добиться статического вызова:
#include "ScopeGuard.h"

class View
{
  int m_ItemsLockCount;

  class ConditionallyUnlockItems // функтор
  {
    View* m_pView;
    bool m_LockItems;
  public:
    ConditionallyUnlockItems(View* pView, bool LockItems)
    {
      m_pView = pView;
      m_LockItems = LockItems;
    }
    void operator()() // вызывается статически
    {
      if (m_LockItems) m_pView->m_ItemsLockCount--;
    }
  };
  friend class ConditionallyUnlockItems; // разрешить функтору доступ к View::m_ItemsLockCount

  void Paint(bool LockItems)
  {
    if (LockItems) m_ItemsLockCount++;
    ON_BLOCK_EXIT(ConditionallyUnlockItems(this, LockItems)); // здесь ScopeGuard
    // использовать Items
    ...
  }
};

Но это уже совсем неуклюжий код.
Подводя итог. D-шные scope(exit) и scope(failure) могут выполнить произвольный кусочек кода с контекстом (контекст — это например локальная переменная LockItems). C++-ный ScopeGuard может всего лишь вызвать функцию (динамически), функтор (статически) или функцию-член (динамически). Поэтому я и утверждаю, что C++-ный ScopeGuard — это слабое подобие D-шных scope(exit) и scope(failure).
Пётр Седов (ушёл с RSDN)
Re[11]: try-finally и scope(exit)
От: Пётр Седов Россия  
Дата: 30.10.07 00:57
Оценка: -1
Здравствуйте, alexeiz, Вы писали:

A>Сравни ON_BLOCK_EXIT со своим первоначальным примером.

Сравниваю. Мой первоначальный пример на D (здесь
Автор: Пётр Седов
Дата: 24.10.07
):

void Func2()
{
  Handle hResA = AllocResA(...);
  scope(exit) FreeResA(hResA);

  Handle hResB = AllocResB(...);
  scope(exit) FreeResB(hResB);

  Handle hResC = AllocResC(...);
  scope(exit) FreeResC(hResC);

  // использовать ресурсы A, B, C
  ...
}

Эквивалентный C++-код с использованием ScopeGuard:
#include "ScopeGuard.h"

void Func_ScopeGuard(...)
{
  Handle hResA = AllocResA(...);
  ON_BLOCK_EXIT(FreeResA, hResA); // здесь ScopeGuard

  Handle hResB = AllocResB(...);
  ON_BLOCK_EXIT(FreeResB, hResB); // здесь ScopeGuard

  Handle hResC = AllocResC(...);
  ON_BLOCK_EXIT(FreeResC, hResC); // здесь ScopeGuard

  // использовать ресурсы A, B, C
  ...
}

Код аналогичен. В C++-варианте функции FreeResA, FreeResB и FreeResC вызываются динамически, но это не страшно. Во-первых, освобождающие функции часто вызываются динамически в любом случае. Например, WinAPI-шная CloseHandle импортируется из динамической библиотеки kernel32.dll, а C-шная fclose обычно импортируется из динамической библиотеки msvcrt.dll. Во-вторых, время освобождения ресурса скорее всего гораздо больше чем время передачи управления.

A>Ты явно упустил из внимания ScopeGuard, когда придумывал аргументы за scope(exit).

C++-ный ScopeGuard не ослабляет аргументы за D-шный scope(exit). Эти механизмы — один и тот же стиль: написать завершающий код не отходя от кассы.

A>А теперь ты пытаешься доказать, что такой-же код можно написать на D.

D-шный scope(exit) мощнее чем C++-ный ScopeGuard. Например, D-шный scope(exit) позволяет легко использовать if-ы и локальные переменные из контекста.

A>Чувствуешь разницу между "смотрите, как D круче: 10 строк C++ кода vs 1 строка D кода" и "на D можно писать код не уступающий C++"?

У нас что, спор «D vs C++»? На D удобнее писать exception-safe-код чем на C++, так как в D помимо деструкторов ещё есть try-finally и scope(exit).
Пётр Седов (ушёл с RSDN)
Re[12]: try-finally и scope(exit)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.10.07 07:20
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

<...примеры поскипаны...>

ПС>Подводя итог. D-шные scope(exit) и scope(failure) могут выполнить произвольный кусочек кода с контекстом (контекст — это например локальная переменная LockItems). C++-ный ScopeGuard может всего лишь вызвать функцию (динамически), функтор (статически) или функцию-член (динамически). Поэтому я и утверждаю, что C++-ный ScopeGuard — это слабое подобие D-шных scope(exit) и scope(failure).


Я согласен, что D-шный scope мощнее, чем C++ная поделка ScopeGuard. Но я думаю, что оба эти механизма ведут к написанию не очень хорошего кода. Имхо, более разумно было бы объеденить логический признак и счетчик элементов в один объект:
class View {
  int m_ItemsLockCount;

  class ItemsLockCountIncrementer {
    bool m_NeedLock;
    int & m_LockCount;
  public :
    ItemsLockCountIncrementer( bool NeedLock, int & LockCount )
      : m_NeedLock( NeedLock ), m_LockCount( LockCount )
      {
        if( m_NeedLock ) ++m_LockCount;
      }
    ~ItemsLockCountIncrementer()
      {
        if( m_NeedLock ) --m_LockCount;
      }
  };

  void Paint( bool LockItems )
    {
      ItemsLockCountIncrementer ItemsLocker( LockItems, m_ItemsLockCount );
      ...
    }
};


На мой взгляд, качество реализации Paint() здесь повышается за счет того, что операции логического инкремента/декремента счетчика здесь записываются всего одной строкой. Это уже атомарная (с точки зрения логики) операция, которую нельзя будет при сопровождении разбавить еще каким-то действиями. В отличии от использования scope-конструкций:
// Так задумывал автор:
void Paint( bool LockItems )
  {
    if( LockItems ) m_ItemsLockCount++;
    scope(exit) m_ItemsLockCount--;
    ...
  }

// А вот так затем сделал майнтайнер:
void Paint( bool LockItems )
  {
    if( LockItems ) m_ItemsLockCount++;
    checkItemsLockCount();
    scope(exit) m_ItemsLockCount--;
    ...
  }

а потом выясниться, что в checkItemsLockCount() выскакивает исключение и управление до scope(exit) не доходит. Соответственно, в случае исключения в checkItemsLockCount значение m_ItemsLockCount окажется неправильным.

Поэтому scope-конструкция, на мой взгляд, больше провоцирует написание некачественного кода, чем традиционный RAII.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Full closures in DMD 2.007
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.11.07 15:02
Оценка: 11 (4)
Да, вот такая вот строчка в Change Log:

Full closure support added.


Подробнее об этом можно прочитать в разделе Functions (пункт Delegates, Function Pointers, and Closures):

A delegate can be set to a non-static nested function:

int delegate() dg;

void test()
{   int a = 7;
    int foo() { return a + 3; }

    dg = &foo;
    int i = dg();    // i is set to 10
}


The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error.
int* bar()
{   int b;
    test();
    int i = dg();    // ok, test.a is in a closure and still exists
    return &b;        // error, bar.b not valid after bar() exits
}



SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Full closures in DMD 2.007
От: _nn_ www.nemerleweb.com
Дата: 03.11.07 15:11
Оценка: :)
Здравствуйте, eao197, Вы писали:

Интересно.
Следующим шагом будет сопоставление паттернов ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.