Комментарии 37
Никогда не понимал, в чем проблема стандартизировать порядок вычисления аргументов в С++.
-4
Никогда не понимал, в чём проблема городить поменьше побочных эффектов.
Ограничения на порядок вычисления аргументов уменьшают свободу манёвра компилятора в раскладывании промежуточных значений по регистрам. Такое решение не особо в духе языка, который позиционирует себя как не вносящий потерь производительности без надобности.
Ограничения на порядок вычисления аргументов уменьшают свободу манёвра компилятора в раскладывании промежуточных значений по регистрам. Такое решение не особо в духе языка, который позиционирует себя как не вносящий потерь производительности без надобности.
+18
Оптимизация же.
+4
Способ забавный конечно, но не особо он сокращает код.
1. Каждый метод должен возвращать указатель на класс, а это значит, что то — что мы сэкономим после будет потерянно уже на этапе описания, плюс код окажется засорен ненужными ретурнами, что почти наверняка в больших классах вызовет неразбериху.
итак для примера из поста:
мы экономим w. \n для каждого вызова метода в замен Worcker&… return this;\n для каждого описания.
(\n — символ переноса строки)
значит нужно где то 5-6 хитро-экономичных вызовов чтобы оправдать излишний код.
2. Второе не менее важное — это быстродействие, любое действие в программе стоит машинного времени, return this не исключение, а так как this значение неоднозначное, то оптимизация вам тут не поможет. Так что не дай бог использовать такой вот код в критических секциях.
1. Каждый метод должен возвращать указатель на класс, а это значит, что то — что мы сэкономим после будет потерянно уже на этапе описания, плюс код окажется засорен ненужными ретурнами, что почти наверняка в больших классах вызовет неразбериху.
итак для примера из поста:
мы экономим w. \n для каждого вызова метода в замен Worcker&… return this;\n для каждого описания.
(\n — символ переноса строки)
значит нужно где то 5-6 хитро-экономичных вызовов чтобы оправдать излишний код.
2. Второе не менее важное — это быстродействие, любое действие в программе стоит машинного времени, return this не исключение, а так как this значение неоднозначное, то оптимизация вам тут не поможет. Так что не дай бог использовать такой вот код в критических секциях.
0
1. Важен не размер описания, а размер вызывающего кода. Вспомните boost — не дай бог случайно залезть в описание, скажем, boost::variadic (ещё до С++11), но зато в вызывающем коде всё очень лаконично.
2. return *this просто возвращает ссылку на текущий объект. Ничего не копируется, накладных расходов минимум, конструкция используется очень часто, хотя бы в std::iostream.
2. return *this просто возвращает ссылку на текущий объект. Ничего не копируется, накладных расходов минимум, конструкция используется очень часто, хотя бы в std::iostream.
+4
Дело в том, что хотя стандарт и гарантирует, что process() будет вызвана перед print_result(), но не гарантируется, что перед аргумент функции print_result будет вычислен после выполнения process().
Вы ошибаетесь.
Стандарт гарантирует следующее:
When calling a function (whether or not the function is inline), there is a sequence point after the evaluation
of all function arguments (if any) which takes place before execution of any expressions or statements in
the function body. There is also a sequence point after the copying of a returned value and before the execution
of any expressions outside the function11)
Таким образом аргументы второй функции не могут быть вычислены до аргументов первой, т.к. они разделены двумя точками следования (sequence point).
+4
Нет вы. Точек следования уже три года как нет. Аргументы функций в полном выражении (читай: до точки с запятой) могут вычисляться вообще как угодно, лишь бы они были вычислены до входа в функцию, которой они нужны.
0
Нет.
См. мой ответ habrahabr.ru/post/215059/#comment_7385513
См. мой ответ habrahabr.ru/post/215059/#comment_7385513
0
В C++11 формулировка другая:
То есть гарантируется только, что аргументы функции будут вычислены до вызова функции, а порядок вычисления других выражений по отношению к вызову функции не определён.
[intro.execution] Par 15:
When calling a function (whether or not the function is inline), every value computation and side effect
associated with any argument expression, or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the body of the called function. [ Note: Value
computations and side effects associated with different argument expressions are unsequenced. — end note ]
Every evaluation in the calling function (including other function calls) that is not otherwise specifically
sequenced before or after the execution of the body of the called function is indeterminately sequenced with
respect to the execution of the called function.
То есть гарантируется только, что аргументы функции будут вычислены до вызова функции, а порядок вычисления других выражений по отношению к вызову функции не определён.
+1
Формулировка другая, но в применении к данному вопросу она дает то же результат.
То что раньше называлось точками следования (sequence point), теперь называется упорядочиванием (sequencing). Что по сути является тем же самым, только позволяет еще описывать поведение неупорядоченного (unsequenced) кода.
Т.е. когда мы говорим что два выражения упорядочены это то же самое что в старом стандарте что между выражениями есть точка следования.
Таким образом интрепретация нового текста стандарта в старых терминах такая:
Это означает существует точка следования между вычислением всех аргументов функции и ее непосредственно выполнением.
Таким образом как старом так и в новом стандарте, вычисление аргументов для двух последовательно идущих в коде функций производится раздельно (если сами вызовы между собой упорядочены, как в данном случае).
То что раньше называлось точками следования (sequence point), теперь называется упорядочиванием (sequencing). Что по сути является тем же самым, только позволяет еще описывать поведение неупорядоченного (unsequenced) кода.
Т.е. когда мы говорим что два выражения упорядочены это то же самое что в старом стандарте что между выражениями есть точка следования.
Таким образом интрепретация нового текста стандарта в старых терминах такая:
every value computation and side effect
associated with any argument expression, or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the body of the called function
Это означает существует точка следования между вычислением всех аргументов функции и ее непосредственно выполнением.
Таким образом как старом так и в новом стандарте, вычисление аргументов для двух последовательно идущих в коде функций производится раздельно (если сами вызовы между собой упорядочены, как в данном случае).
+2
Там написано ровно то, что написано: «все вычисления и побочные эффекты, связанные с вычислением аргументов вызываемой функции или самой вызываемой функции, выполняются перед вычислением тела вызываемой функции». Здесь нет ничего о том, что находится вне тела функции.
0
Точки следование и упорядочивание — это не одно и то же. Точка следования — это такой барьер для побочных эффектов: все побочные эффекты должны быть применены и видимы после точки следования для всех остальных выражений. Упорядочивание касается только выражений, которые упорядочены относительно друг друга. Плюс, для упорядочивания есть три понятия: определённо упорядочены, неопределённо упорядочены и не упорядочены. Всё, что явно не прописано, считается не упорядоченным.
0
Задумался.
Пойду перечитаю стандарт :)
Пойду перечитаю стандарт :)
0
Энивей, что-то меня понесло. Даже в C++03 аргументы могут быть вычислены до вызова всех функций полного выражения.
Точки следования касаются побочных эффектов. То есть они гарантируют, что внутри тела print_result
Но порядка вычисления аргументов нескольких функций это не касается.
Точки следования касаются побочных эффектов. То есть они гарантируют, что внутри тела print_result
data == 185
. И упорядочивание тоже это гарантирует (вызовы функций внутри одного полного выражения не пересекаются, выражение слева после точки вычисляется перед выражением справа).Но порядка вычисления аргументов нескольких функций это не касается.
data + 2
может вычисляться как при data == 0
(сначала вычисляются все аргументы, потом вызывается process, потом print_resutl), так и при data == 185
(сначала аргументы process, потом вызов process, потом аргументы print_result, потом print_result).0
Статья заканчивается невероятно неожиданно. Опасные ситуации наверняка есть и много, если раскрутить ситуации, касающиеся созданий, удалений объектов, исключений и прочих классических недопонимаемых ситуаций. Ещё предположу, что с константными методами будут неудобства, так как после первого же константного в цепочку соберутся только константные.
А вообще способ странноватый, и совсем не понимаю, за что его любят в java.
А вообще способ странноватый, и совсем не понимаю, за что его любят в java.
+2
Этим паттерном обычно компенсируют отсутствие именованных параметров в с++
+2
Самый хороший пример из мира плюсов — потоковые операторы из stl. Как method chaining, только функциональнее.
+3
Тем временем, этот паттерн (это называется fluent interface) очень популярен в .NET и работает там корректно. Чтобы не был определен порядок вызовов — это же как сильно напортачить надо? Ужас. Вот из-за таких вещей портится впечатление от плюсов в целом.
-3
Порядок вызовов определён. Неопределён лишь порядок вычисления их аргументов. Что, как показано, тоже довольно неприятно. При желании можно провести аналогию с функциональными языками.
+1
Достаточно было упомянуть, что этот паттерн называется Fluent interface (удивительно что автор топика этого знает).
0
Жалко, что в Си нет with() do.
0
Паттерн конечно интересный, но применять его стоит аккуратно. В большинстве случаев эта цепочка не рандомная, и в ней нельзя поменять местами вызовы методов. Как пользователь класса я не хочу знать о том, в каком порядке мне их звать, я хочу иметь один метод, к примеру doWork(), который сделает меня счастливым.
Его можно использовать только в том случае, когда методы на самом деле независимы (или почти независимы) и их можно комбинировать в любом порядке. Например, всякого рода парсеры, сериализаторы, etc.
Его можно использовать только в том случае, когда методы на самом деле независимы (или почти независимы) и их можно комбинировать в любом порядке. Например, всякого рода парсеры, сериализаторы, etc.
0
Я видел места где это может быть полезно — декларативная инициализация объекта. Декларативная разметка не подразумевает зависимости от порядка, и каждый аспект не зависит от другого:
view->setSize(10, 10)->setAlign(Stretch)->setSnap(true)
и т.п.
При использовании в других целях, вылезают проблемы, которые описаны в статье и в комментариях выше.
view->setSize(10, 10)->setAlign(Stretch)->setSnap(true)
и т.п.
При использовании в других целях, вылезают проблемы, которые описаны в статье и в комментариях выше.
+1
Декларативную инициализацию, как и любую другую инициализацию, лучше не выносить за пределы вызова конструктора. Бонусов от этого масса, в том числе возможность сделать объект immutable. А при инициализации через конструктор, даже самой изощрённой, описанное в топике мало пригодится. Ну и самая красивая декларативность в плюсах — она на шаблонах и простых объектах.
+2
Верно. Но я показал пример а-ля виджет. Он не может быть неизменяемый. Его конструктор лопнет от всех инициализаций. Все его свойства и так пишутся отдельными методами, вот в этом случае этот патерн очень даже подходит.
+2
А при инициализации через конструктор, даже самой изощрённой, описанное в топике мало пригодится.
Спрятать страшный конструктор с десятью аргументами, сделать билдер. А в билдере разбираемый здесь чейнинг методов будет смотреться просто идеально.
0
GUI -библиотека Ultimate++ использует этот паттерн
0
Буквально пару дней назад отловил баг с этим паттерном:
Догадайтесь, где баг. Можно сказать, что автор (не я) сам себе злобный буратино. Однако, осадочек, как говорится, остался.
worker const & w = worker()
.set_data(data_t{})
.process()
.send_result()
.print_log();
Догадайтесь, где баг. Можно сказать, что автор (не я) сам себе злобный буратино. Однако, осадочек, как говорится, остался.
+2
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Method chaining