Еще короче: я не знаю, почему вы, ребята, настаиваете на том, чтобы поместить шаблон в класс охраны.
#include
class scope_guard {
public:
template
scope_guard(Callable && undo_func) try : f(std::forward(undo_func)) {
} catch(...) {
undo_func();
throw;
}
scope_guard(scope_guard && other) : f(std::move(other.f)) {
other.f = nullptr;
}
~scope_guard() {
if(f) f(); // must not throw
}
void dismiss() noexcept {
f = nullptr;
}
scope_guard(const scope_guard&) = delete;
void operator = (const scope_guard&) = delete;
private:
std::function f;
};
Обратите внимание, что код очистки не бросается, иначе вы получаете в том же случае, что и при метании деструкторов.
Использование:
// do step 1
step1();
scope_guard guard1 = [&]() {
// revert step 1
revert1();
};
// step 2
step2();
guard1.dismiss();
Мое вдохновение было тем же статьей DrDobbs , что и для OP.
Редактировать 2017/2018: После просмотра (некоторые из) презентации Андрея , с которой связан Андре (я пропустил до конца, где он сказал «Больно близко к идеалу!»). Я понял, что это выполнимо. Большую часть времени вы не хотите иметь дополнительных охранников для всего. Вы просто делаете что-то, и, в конце концов, это либо преуспевает, либо должен произойти откат.
Изменить 2018: добавлена политика выполнения, которая устраняет необходимость вызова dismiss
.
#include
#include
class scope_guard {
public:
enum execution { always, no_exception, exception };
scope_guard(scope_guard &&) = default;
explicit scope_guard(execution policy = always) : policy(policy) {}
template
scope_guard(Callable && func, execution policy = always) : policy(policy) {
this->operator += (std::forward(func));
}
template
scope_guard& operator += (Callable && func) try {
handlers.emplace_front(std::forward(func));
return *this;
} catch(...) {
if(policy != no_exception) func();
throw;
}
~scope_guard() {
if(policy == always || (std::uncaught_exception() == (policy == exception))) {
for(auto &f : handlers) try {
f(); // must not throw
} catch(...) { /* std::terminate(); ? */ }
}
}
void dismiss() noexcept {
handlers.clear();
}
private:
scope_guard(const scope_guard&) = delete;
void operator = (const scope_guard&) = delete;
std::deque> handlers;
execution policy = always;
};
Использование:
scope_guard scope_exit, scope_fail(scope_guard::execution::exception);
action1();
scope_exit += [](){ cleanup1(); };
scope_fail += [](){ rollback1(); };
action2();
scope_exit += [](){ cleanup2(); };
scope_fail += [](){ rollback2(); };
// ...
Определите "правильно".
i18n сортировка полностью зависит от вашего местонахождения.
Поэтому я полностью согласен с PA, что это не ошибка: поведение по умолчанию Sort работает так, чтобы i18n работал правильно.
Как упоминает Джерри , TStringList.Sort использует AnsiCompareStr и AnsiCompareText (Я объясню в нескольких строках, как это делается).
Но: TStringList гибкий, он содержит Sort, CustomSort и CompareStrings, которые все виртуальные (поэтому их можно переопределить в классе-потомке)
.
Кроме того, при вызове CustomSort можно подключить собственную функцию Compare.
В данном ответе находится функция Сравнить, которая делает то, что Вам нужно:
CustomSort определено следующим образом:
procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
if not Sorted and (FCount > 1) then
begin
Changing;
QuickSort(0, FCount - 1, Compare);
Changed;
end;
end;
По умолчанию метод Sort имеет очень простую реализацию, передавая функцию по умолчанию Compare с вызовом StringListCompareStrings:
procedure TStringList.Sort;
begin
CustomSort(StringListCompareStrings);
end;
Итак, если вы определите свой собственный TStringListSortCompare совместимый метод Compare, то вы можете определить свой собственный метод сортировки.
TStringListSortCompare определяется как глобальная функция, принимающая TStringList и два индекса, ссылающихся на элементы, которые вы хотите сравнить:
type
TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;
Вы можете использовать StringListCompareStrings в качестве руководства по реализации вашего собственного:
function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := List.CompareStrings(List.FList^[Index1].FString,
List.FList^[Index2].FString);
end;
Итак, по умолчанию TStringList. Сортировка откладывается на TList.CompareStrings:
function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
if CaseSensitive then
Result := AnsiCompareStr(S1, S2)
else
Result := AnsiCompareText(S1, S2);
end;
Который затем использует лежащую внизу функцию Windows API CompareString со стандартной пользовательской локалью LOCALE_USER_DEFAULT:
function AnsiCompareStr(const S1, S2: string): Integer;
begin
Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
PChar(S2), Length(S2)) - 2;
end;
function AnsiCompareText(const S1, S2: string): Integer;
begin
Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
Length(S1), PChar(S2), Length(S2)) - 2;
end;
Наконец-то нужная вам функция Compare. Снова ограничения:
This is the code:
function StringListCompareStringsByOrdinalCharacterValue(List: TStringList; Index1, Index2: Integer): Integer;
var
First: string;
Second: string;
begin
First := List[Index1];
Second := List[Index2];
if List.CaseSensitive then
Result := CompareStr(First, Second)
else
Result := CompareText(First, Second);
end;
Delphi isn't closed, quite противоположное: часто это действительно гибкая архитектура.
Часто это просто немного копать, чтобы увидеть, где вы можете подключиться к этой гибкости.
--jeroen
AnsiCompareStr / AnsiCompareText учитывает больше, чем количество символов. Они учитывают локаль пользователей, поэтому "e" будет сортироваться вместе с "é", "ê" и т.д.
Для того, чтобы он отсортировался в порядке Ascii, используйте пользовательскую функцию сравнения , как описано здесь
AnsiCompareStr (CompareString with LOCALE_USER_DEFAULT) имеет ошибку, так как получает символы с пунктуацией, равной:
e1. é1 e2 é2
правильный порядок (например, для чешского языка):
e1 e2 é1 é2
Кто-нибудь знает, как избежать этой ошибки при заказе?
11.2.2010: Я должен извиниться за то, что описанное поведение полностью соответствует лингвистическим правилам. Хотя я думаю, что это глупо и "плохо", но это не ошибка в функции API.
Проводник в Windows XP использует так называемое интуитивное упорядочивание имен файлов, которое дает лучшие результаты, но не может быть использовано программно.