Здесь следовало бы либо вызвать delete, либо хотя бы отдать хранящийся в переменной interface адрес наружу в любом случае, чтобы об этом мог позаботиться вызывающий код
а ещё лучше — std::unique_ptr::release
И, да, ребята, категорически умоляю, прячьте объяснения под кат, а то совсем неинтересно становится читать
Вариант с несколькими уровнями вложенности — да, если их больше 2-х это напрягает, хотя, на мой вкус, всё равно читается лучше, чем то, что было изначально.
Вариант с одним if-ом — плох тем, что даёт, пусть и небольшие, лишние накладные расходы на создание неиспользуемых объектов.
Ну, погуглите one return only, будет много интересного. И, да, я не считаю это большой проблемой в исходном варианте, гораздо хуже там неоднократный copy-paste блока после if.
Он читается лучше, т.к. при чтении банально меньше нужно елозить глазами вниз по экрану. И антипаттерн он только в C++, в «чистом» C, где широко используются коды ошибок, это — обычное дело. Конечно, больше 3-х уровней отступов нормальные люди без острой необходимости не делают.
P.S. «Антипаттерн» — обычное слово-идеон. Причисление к паттернам и антипаттернам, как правило, происходит на волне очередного хайпа. В своё время что только не объявляли антипаттерном: коды возврата, null-объекты, goto, более одного return, отсутствие Yoda-style в сравнении. А оказалось, что и коды возврата, и null-объект — вполне рабочие подходы, goto широко используется в системном программировании на C для обработки ошибок, yoda-style используют не только лишь не все, а вообще мало кто.
std::string aStr;
int ok = readLine(aStr);
if (!ok) {
processError();
return;
}
std::string bStr;
ok = readLine(bStr);
if (!ok) {
processError();
return;
}
int a = 0;
ok = parseInt(aStr, a);
if (!ok) {
processError();
return;
}
int b = 0;
ok = parseInt(bStr, b);
if (!ok) {
processError();
return;
}
int result = 0;
ok = safeAdd(a, b, result);
if (!ok) {
processError();
return;
}
std::cout << result << std::endl;
«Лапшу» можно с любым механизмом обработки ошибок сотворить. А если вот так:
std::string aStr;
if (readLine(aStr))
{
std::string bStr;
if (readLine(bStr))
{
int a = 0, b = 0;
if (parseInt(aStr, a) && parseInt(bStr, b) && safeAdd(a, b, result))
{
std::cout << result << std::endl;
return;
}
}
}
processError();
Или даже так — ценой, возможно, преждевременного создания объектов (надеюсь, компиляторы/библиотеки, когда-нибудь станут достаточно умными, чтобы сделать это чуть-чуть дешевле:
std::string aStr, bStr;
int a, b, result;
if (
readLine(aStr) && readLine(bStr) &&
parseInt(aStr, a) && parseInt(bStr, b) &&
safeAdd(a, b, result)
)
std::cout << result << std::endl;
else
processError();
Это мнение Саттера, как частного лица. Если бы это было мнение комитета по стандартизации, это было бы в стандарте. Мотивировка — откровенно слабая:
So as soon as any of the special functions is declared, the others should all be declared to avoid unwanted effects like turning all potential moves into more expensive copies, or making a class move-only.
Т.е. запрещайте, чтобы избежать неких «нежелательных эффектов». А никаких эффектов и без вмешательства кодера не будет, поведение компилятора в этом случае выглядит вполне разумным. Ну и традиционное, как пьяный дед мороз под новый год, «explicit is better than implicit»:
Defining only the move operations or only the copy operations would have the same effect here, but stating the intent explicitly for each special member makes it more obvious to the reader.
P.S. лично я предпочитаю не загаживать исходный код вещами, ничего не дающими ни кодеру, ни компилятору
Запрещать копирование не нужно, т.к. при наличии перемещающих конструктора и оператора присвоения компилятор не станет генерировать их копирующие аналоги.
а ещё лучше — std::unique_ptr::release
И, да, ребята, категорически умоляю, прячьте объяснения под кат, а то совсем неинтересно становится читать
Исходный вариаент кода — плох многословностью, copy-paste-ом, множественными return.
Вариант с несколькими уровнями вложенности — да, если их больше 2-х это напрягает, хотя, на мой вкус, всё равно читается лучше, чем то, что было изначально.
Вариант с одним if-ом — плох тем, что даёт, пусть и небольшие, лишние накладные расходы на создание неиспользуемых объектов.
Ещё варианты есть? По-моему, альтернативы нет.
P.S. «Антипаттерн» — обычное слово-идеон. Причисление к паттернам и антипаттернам, как правило, происходит на волне очередного хайпа. В своё время что только не объявляли антипаттерном: коды возврата, null-объекты, goto, более одного return, отсутствие Yoda-style в сравнении. А оказалось, что и коды возврата, и null-объект — вполне рабочие подходы, goto широко используется в системном программировании на C для обработки ошибок, yoda-style используют не только лишь не все, а вообще мало кто.
«Лапшу» можно с любым механизмом обработки ошибок сотворить. А если вот так:
Или даже так — ценой, возможно, преждевременного создания объектов (надеюсь, компиляторы/библиотеки, когда-нибудь станут достаточно умными, чтобы сделать это чуть-чуть дешевле:
Т.е. запрещайте, чтобы избежать неких «нежелательных эффектов». А никаких эффектов и без вмешательства кодера не будет, поведение компилятора в этом случае выглядит вполне разумным. Ну и традиционное, как пьяный дед мороз под новый год, «explicit is better than implicit»:
P.S. лично я предпочитаю не загаживать исходный код вещами, ничего не дающими ни кодеру, ни компилятору
Запрещать копирование не нужно, т.к. при наличии перемещающих конструктора и оператора присвоения компилятор не станет генерировать их копирующие аналоги.