2009-08-08 2 views
18

При использовании языка с попыткой/уловком /, наконец, полезны инструкции D/s failure/success/exit scope? D, похоже, не может окончательно объяснить, почему эти утверждения используются в D. Но с таким языком, как C#, это полезно? Я разрабатываю язык, поэтому, если я увижу много профи, я его добавлю.Является ли D недостатком области/успеха/выхода?

+0

У вас есть блог или какой-либо сайт? –

+0

Ctrl Alt D-1337: Нет. Вы должны сообщить мне (мой адрес электронной почты в моем профиле). Я могу опубликовать его под другим именем. (У меня разные имена пользователей для разных интересов) – 2009-08-08 20:30:06

+5

D наконец-то – BCS

ответ

39

scope(X) не надо таким же образом, что for не является необходимым, если Вы имеете if и goto.

Вот перефразировать пример из некоторого кода я пишу сегодня:

sqlite3* db; 
sqlite3_open("some.db", &db); 
scope(exit) sqlite3_close(db); 

sqlite3_stmt* stmt; 
sqlite3_prepare_v2(db, "SELECT * FROM foo;", &stmt); 
scope(exit) sqlite3_finalize(stmt); 

// Lots of stuff... 

scope(failure) rollback_to(current_state); 
make_changes_with(stmt); 

// More stuff... 

return; 

Contrast это с помощью Try/уловом:

sqlite3* db; 
sqlite3_open("some.db", &db); 
try 
{ 
    sqlite3_stmt* stmt; 
    sqlite3_prepare_v2(db, "SELECT * FROM foo;", &stmt); 
    try 
    { 
     // Lots of stuff... 
     try 
     { 
      make_changes_with(stmt); 

      // More stuff... 
     } 
     catch(Exception e) 
     { 
      rollback_to(current_state); 
      throw; 
     } 
    } 
    finally 
    { 
     sqlite3_finalize(stmt); 
    } 
} 
finally 
{ 
    sqlite3_close(db); 
} 

код превратился в spaghetti, распространение ошибки восстановление по всему магазину и вытеснение уровня отступов для каждого блока try. Версия с использованием области (X), на мой взгляд, значительно читаема и понятна.

+2

Золото не только потому, что вы должны мне, как это может стать спагетти, но и как код настолько специфичен для функции, что деструкторы должны/не могут быть решением. – 2009-08-08 20:23:54

+1

Этот первый пример кода очень приятный. Это глоток свежего воздуха. Мы все так привыкли читать вторую переведенную форму, что первая выглядит странно, но она имеет ту же уверенность и прогрессию, что и код «раннего возвращения» или «раннего броска»: рассмотрим проблему A, укажите разрешение, забудьте о A и переходите к рассмотрению проблемы B, укажите разрешение, забудьте о B и двигайтесь дальше. – seh

9

try/catch/наконец заставляет уровень гнездования; Охранники не имеют. Кроме того, они позволяют вам писать код очистки в той же «области», что и код выделения, поэтому больше не нужно «открывать файл, прокручивать до конца функции, закрывать файл, прокручивать вверх до функции».

В принципе, это просто более удобное выражение обработки try/catch/finally - что-нибудь вы можете сделать с try/catch /, наконец, вы можете сделать с защитой области и наоборот.

Стоило ли? Я фанат D (так, предвзятый), но я бы сказал определенно.

5

Отличительная характеристика отказа - выход из успеха-выхода весьма полезен некоторое время - у меня нет реального опыта в мире с D, но инструкция Python with также позволяет это, и я считаю это очень полезным, например, для совершить или отменить транзакцию БД, которая была открыта в защищенной части тела.

Когда я объяснил эту новую функцию Python (она уже давно существует ;-) для друзей и коллег, которые являются гуру на C++ и Java, я обнаружил, что они сразу поняли и увидели интерес к такой функции (У Python тоже есть finally, но это не помогает отличить успех от отказа, как и на других языках [или C++ «RAII-уничтожение автоматических переменных в блочном эквиваленте»).

+0

Я не понимаю. Я прочитал это http://effbot.org/zone/python-with-statement.htm Похоже, он позволяет запускать ctor и dtor. Не работает ли это без инструкции? Я не знаю питона хорошо или что на самом деле происходит – 2009-08-08 04:23:50

+1

Точка в том, что специальный метод диспетчера контекста '__exit__' вызывается с информацией о том, какое исключение распространяется, если таковое имеется; таким образом, менеджер контекста для операций БД, например, может различать случаи успеха, гарантируя фиксацию БД и отказы, требующие откат БД. Вы говорите о совершенно другой проблеме: dtors, как таковой, может быть запущен в попытке /, наконец, просто синтаксически неуклюже, чем RAII (смотрите THAT up! -), но функционально эквивалентны. Но отличать успех от неудачи, в некоторых случаях, CRUCIAL! –

6

Отказ от ответственности Я тоже фанат-фанат.

someRiskyFunctionThatMayThrow(); 
lock(); 
/* we have definitly got the lock so lets active 
a piece of code for exit */ 
scope(exit) 
    freelock(); 

По сравнению с:

try 
{ 
    someRiskyFunctionThatMayThrow(); 
    lock(); 
} 
finally 
{ 
    freeLockIfNotGot(); 
} 
2

@DK, Следует отметить, в C++ (и Java я думаю) вы можете легко использовать «анонимный» класс, чтобы выполнить то же самое, Scope (выход):

int some_func() 
{ 
    class _dbguard { sqlite3* db; 
        _dbguard(const _dbguard&); _dbguard& operator=(const _dbguard&); 
       public: 
        _dbguard(const char* dbname) { sqlite3_open(dbname, &db);} 
        ~_dbguard() {sqlite3_close(db);} 
        operator sqlite3*() { return db; } 

    } db("dbname"); 
    ... 
} 

И если вы сделали это более одного раза, сразу же превратив его в полноценный класс, чтобы обрабатывать RAII для вас. Это так просто писать, я не могу представить себе программу на C++, которая использует sqlite (как используется в примере) без создания таких классов, как CSqlite_DB и CSqlite_Stmt.На самом деле оператор sqlite3 *() должен быть anathama и полная версия будет просто методы, которые обеспечивают операторы:

class CSqlite3_DB { 
    ... 
    CSqlite3_Stmt Prepare(const std::string& sql) { 
     sqlite3_stmt* stmt = 0; 
     try { 
      sqlite3_prepare_v2(db, sql.c_str(), &stmt); 
     } catch (...) {} 
     return stmt; 
    } 
}; 

Что касается первоначального вопроса, я бы сказал, что ответ «не очень». Надлежащее уважение к DRY скажет вам взять эти длинные блоки try/catch/finally и преобразовать их в отдельные классы, которые скрывают части try/catch от остальной части, где они могут (в случае масштаба (сбоя)), и делают управление ресурсами прозрачно (в случае области (выход)).

+0

отличный ответ. – 2010-06-21 18:45:54

+1

... хотя я укажу, объем (выход) составляет около 200 символов меньше, чем любая из версий :-) –

+0

На самом деле, поскольку я пишу это, я предпочитаю метод D. Когда я действительно думал о масштабе (неудаче) и объеме (успехе), я был продан. Способ RAII не может дублировать эти функции без уродливой поддержки MACRO. Тем не менее, для примера SqlLite полный класс оболочки C++ является «правильным» решением на C++. – jmucchiello

5

Следует отметить, что для C++ доступны также область действия (сбой), область действия (сбой) и область (успех).

  • Для области (выхода) есть библиотека Boost.ScopeExit.
  • Для области (сбоя) и объема (успеха) есть библиотека stack_unwinding.

следующий синтаксис поддерживается, случай 1:

try 
{ 
    int some_var=1; 
    cout << "Case #1: stack unwinding" << endl; 
    scope(exit) 
    { 
     cout << "exit " << some_var << endl; 
     ++some_var; 
    }; 
    scope(failure) 
    { 
     cout << "failure " << some_var << endl; 
     ++some_var; 
    }; 
    scope(success) 
    { 
     cout << "success " << some_var << endl; 
     ++some_var; 
    }; 
    throw 1; 
} catch(int){} 

печатает:

Case #1: stack unwinding 
failure 1 
exit 2 

Случай 2:

{ 
    int some_var=1; 
    cout << "Case #2: normal exit" << endl; 
    scope(exit) 
    { 
     cout << "exit " << some_var << endl; 
     ++some_var; 
    }; 
    scope(failure) 
    { 
     cout << "failure " << some_var << endl; 
     ++some_var; 
    }; 
    scope(success) 
    { 
     cout << "success " << some_var << endl; 
     ++some_var; 
    }; 
} 

печатает:

Case #2: normal exit 
success 1 
exit 2 
+0

wtf столько кода !? Я реализовал SCOPE_EXIT, SCOPE_SUCCESS и SCOPE_FAIL в 6 строках кода C++ 11. Все, что я делаю, - это функция лямбда. Но +1 в любом случае. Ни в коем случае я не включаю те заголовки tho. Очень перебор.Heres 3 lines, другие 3 - marco defs, специфичные для моего кода http://pastebin.com/zaLZ6fP7 – 2012-10-21 04:28:02

+1

@ acidzombie24: 1. Ваше решение не работает должным образом, проверьте это: http://ideone.com/IcWMEf никаких исключений внутри ~ Test(), но печатается «сбой». –

+0

@ acidzombie24: 2. Для C++ 11-единственное решение на самом деле короче. Но эта библиотека хорошо работает и для C++ 98/C++ 03. Большая часть кода связана с эмуляцией «lambdas» для C++ 98/C++ 03. –

Смежные вопросы