Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[13.59.100.42] |
|
Страницы: (32) « Первая ... 27 28 [29] 30 31 ... Последняя » ( Перейти к последнему сообщению ) |
Сообщ.
#421
,
|
|
|
Именно что выглядит. Так-то он хуже. Потому что не избавляет пользователей scope()-ов от того, чтобы быть постоянно быть во внимании и заниматься рутинным делом: проверять успех небезотказной операции и клепать код отмены транзакций. RAII требует этого только от автора.
Ну и опять же, если пользователей не больше авторов , тогда scope()-ы окупаются. Но в промышленных решениях это редкие события. Добавлено Объективно – пару лет. В бусте подобные штуки появились быстро, и в следующий Стандарт заехали без проблем. |
Сообщ.
#422
,
|
|
|
Цитата Qraizer @ Объективно – пару лет Враки! Я с лямбдами в Perl'е работал с 1998 года (и то - я опаздун в освоении Перла). В сях - "не прошло и пол-года". |
Сообщ.
#423
,
|
|
|
Цитата applegame @ Угу. А если:Посмотри на свою иммитацию scope: scope1, scope2, scope3... - что это за мерзкие нумерованные переменные, которые нигде не задействованы? Вот где костыль-то. #define CAT(X, Y) X##Y #define VAR(X, Y) CAT(X, Y) #define SCOPE ScopeD::scope VAR(dummy, __LINE__) int main() { using namespace ScopeD; SCOPE (failure, [](){ std::cout << "scope(exit) 1" << std::endl; }); throw std::runtime_error("exception"); SCOPE (failure, [](){ std::cout << "scope(exit) 2" << std::endl; }); } |
Сообщ.
#424
,
|
|
|
Qraizer, как уж на сковородке! Но таки - аcилил?! )))
Добавлено Qraizer, наверное можно было бы и всю лямбду в макро загнать? |
Сообщ.
#425
,
|
|
|
Цитата JoeUser @ Кому вдруг критично , пусть юзают. Я так не считаю. И даже не думаю, что кому надо было бы, не написал бы сам молча, а запросил саппорт "памагите".Но таки - аcилил?! ))) Цитата JoeUser @ М-м, нет. В общем случае лямбда может быть очень сложной, препроцессор поломается на разделителях. Да и зачем? Препроцессор штука, конечно, мощная, но ну её. наверное можно было бы и всю лямбду в макро загнать? |
Сообщ.
#426
,
|
|
|
Qraizer, а вот тут
// ... Guard sameAppGuarded([=]() { CloseHandle(sameApp); }); // ... Может в лямбде лучше по ссылке захватывать? Добавлено Дааа ... у этого RAII тоже есть побочки. Решил переписать "по-фэншую", и как оказалось, выплыла шляпа Когда без RAII - критикуют мол, забудешь освободить ресурс. А как оказалось, в моей проге, пришлось в каждую лямбду вставить проверку на ошибку. Типа, если действительно была ошибка - освобождать, а если нет - пропустить. И только в одной лямбде это не потребовалось. Поэму рисуется контр-аргумент: не поставишь проверку необходимости освобождения - получишь ошибку времени исполнения. Добавлено ЗЫ: Qraizer, мне понравились твои гварды! Аккуратнее всего получается. |
Сообщ.
#427
,
|
|
|
Цитата JoeUser @ А как оказалось, в моей проге, пришлось в каждую лямбду вставить проверку на ошибку. Типа, если действительно была ошибка - освобождать, а если нет - пропустить. И только в одной лямбде это не потребовалось. Поэму рисуется контр-аргумент: не поставишь проверку необходимости освобождения - получишь ошибку времени исполнения. Возможно, ты что-то не так делаешь, например, не передаешь владение ресурсом. И о каких лямбдах речь? Можешь код привести? |
Сообщ.
#428
,
|
|
|
Цитата D_KEY @ Можешь код привести? Ну вот кусок: // ... // инициализация библиотеки if (libssh2_init(0) != 0) { sftpError = sftp_error::init_error; return false; } Guard Guard_init([&]() { if (sftpError != sftp_error::no) libssh2_exit(); }); // поиск адреса хоста // ... // ... // ... libssh2_exit() нужно вызывать только тогда, когда что-то потом пошло не так. Но если все отработало нормально - libssh2 должна остаться проинициализированной. |
Сообщ.
#429
,
|
|
|
Цитата JoeUser @ libssh2_exit() нужно вызывать только тогда, когда что-то потом пошло не так. Но если все отработало нормально - libssh2 должна остаться проинициализированной. Остаться-то должна, но потом где-то же должен быть вызов libssh2_exit все равно. Вот туда и надо передать владение. А не через guard' ы. |
Сообщ.
#430
,
|
|
|
Цитата D_KEY @ Остаться-то должна, но потом где-то же должен быть вызов libssh2_exit все равно. Это в деструкторе вызывается: sftp_class::~sftp_class() { if (sftpError != sftp_error::winsocket_error) { if (sftpState == sftp_state::logged_in) Logoff(); // ◄────── вот тут и вызовется libssh2_exit #ifdef WIN32 WSACleanup(); #endif } } } |
Сообщ.
#431
,
|
|
|
Ну вот в случае RAII у тебя и будет объект ssh_initializer или что-то вроде того. Который в деструкторе сделает ssh2_exit, если владеет объектом. Этот объект делаешь полем класса. Локально в функции, где идет init, ты создаешь временный объект этого класса и только в случае успеха передаешь владение полю.
Примерно так. |
Сообщ.
#432
,
|
|
|
Тогда нарушается логика поведения класса. В методе Login происходит полная инициализация подключение к серверу, ну и подключение. Если логин не прошел - экземпляр класс болтается с состоянием ошибки, по не будет удален (ну или еще попытки логина). В деструкторе вызывается Logoff, если нужно - вот он и рвет все соединения (опять же, если класс не в состоянии ошибки).
|
Сообщ.
#433
,
|
|
|
Цитата JoeUser @ Решил переписать "по-фэншую", и как оказалось, выплыла шляпа Когда без RAII - критикуют мол, забудешь освободить ресурс. А как оказалось, в моей проге, пришлось в каждую лямбду вставить проверку на ошибку. Типа, если действительно была ошибка - освобождать, а если нет - пропустить. Если бы переписал по феншую, скорее всего шляпы не было бы. Значит написал не по феншую Если у тебя вызов сишной функции возвращает код возврата - кто тебе мешает кидать исключение в конструкторе RAII обертки? Тогда и проверять не пришлось бы в деструкторе. |
Сообщ.
#434
,
|
|
|
Цитата JoeUser @ Тогда нарушается логика поведения класса ... Если логин не прошел - экземпляр класс болтается с состоянием ошибки Плохая практика, не надо так делать. Прочитай про инварианты класса. |
Сообщ.
#435
,
|
|
|
Цитата JoeUser @ Ну так это не RAII. В RAII нужно оборачивать ресурс, для которого известно время жизни, обозначив его {}, а не который когда захотел, получил, когда захотел, освободил. Если когда захотел, то это ж ничем не отличается от ручного управления. Посмотри в пример использования во втором "костыле", это пример из реальной программы... впрочем, мне не жалко скопипастить и даже прокомментировать:Типа, если действительно была ошибка - освобождать, а если нет - пропустить. И только в одной лямбде это не потребовалось. // Атомарно получить ресурс монопольного доступа к образу приложения и захватить его HANDLE sameApp = CreateMutex(NULL, TRUE, uniqName.c_str()); // Вручную проверить успех получения ресурса if (sameApp == NULL) return static_cast<void>(logMsg("CreateMutex() failed", GetLastError())); // Зарегистрировать освобождение ресурса Guard sameAppGuarded([=]() { CloseHandle(sameApp); }); // Проверить, удалось ли захватить монополию или же доступ уже ранее (GetLastError() будет равен ERROR_ALREADY_EXISTS) был кем-то захвачен if (GetLastError() == ERROR_ALREADY_EXISTS) if (WaitForSingleObject(sameApp, INFINITE) != WAIT_OBJECT_0) // подождать возможности монопольного доступа // При ошибке монополизации гвард сам освободит ресурс return static_cast<void>(logMsg("Recursive run detected for " + name.filename().string(), GetLastError())); // Монополия успешно получена, зарегистрировать его отдачу другим страждущим Guard sameAppLocked([=]() { ReleaseMutex(sameApp); }); // Локальные границы времени жизни файлов, в которые перенаправляется консольный ввод/вывод { SECURITY_ATTRIBUTES attr = { sizeof(attr), NULL, TRUE }; // Файл для перенаправленного консольного ввода HANDLE hIn = CreateFile((newName.parent_path() / "stdin.txt").string().c_str(), FILE_GENERIC_READ, FILE_SHARE_DELETE,&attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // Зарегистрировать его закрытие Guard hInGuarded ([=]() { CloseHandle(hIn); }); /* и так для всех трёх стандартных консольных устройств, ну и кроме того там ещё куча логики работы с образом приложения */ } // и тут эти локальные границы заканчиваются, файлы с консольным вводов/выводом закрываются гвардами. // Ниже есть ещё чуток кода для логгирования и ещё по мелочи, и гварды позаботятся и об освобождении образа приложения от монополии, и об освобождении ресурса |