Этот вопрос граничит с вопросом о мнении, поэтому мне, вероятно, следовало бы не говорить, что я, вероятно, не буду использовать эти два интерфейса в одной и той же программе, потому что я стараюсь избегать API, в которых тип данных иногда передается по значению идругие времена по ссылке.Но это только я, поэтому я ограничу остальную часть ответа причиной, по которой вы можете использовать интерфейс, который передает объект средней тяжести по значению.Если вы хотите услышать причины, по которым исходный кодер выбрал этот стиль, вам следует спросить его об этом напрямую.
Первый момент заключается в том, что большинство современных компиляторов смогут избежать копирования, если у них есть доступ к основной части кода.вызываемая функция и сама вызываемая функция достаточно легки, чтобы их можно было встроить.Эти условия, похоже, применяются в случае функций из ссылочного кода, поэтому использование вызова по значению, вероятно, не требует никаких затрат.[Примечание 1] Таким образом, если стиль API предоставляет полезную информацию для программы чтения кода, то ее можно считать полезной.
Теперь рассмотрим прототипы параметров X const *
и X
.В обоих случаях мы знаем, что переданный аргумент не будет изменен, поэтому нам, конечно, не нужно его копировать.
Но все же может возникнуть обеспокоенность по поводу времени жизни аргумента.Если вызываемая функция берет указатель и сохраняет этот указатель в объекте, который переживет вызов, то нам нужно беспокоиться о принадлежности переданного объекта.По сути, нам нужно было бы передать владение объектом вызываемой функции, а также убедиться, что объект не имеет автоматического времени жизни.В частности, мы не можем вызвать функцию с временным вызовом, и у нас могут возникнуть некоторые сомнения относительно вызова функции с объектом со статическим временем жизни (которое не может быть free
d).
С другой сторонывызов по значению явно не накладывает никаких требований на вызывающего.Если вызываемая функция хочет сохранить переданный объект, она отвечает за создание копии и удаление копии, когда она больше не нужна.Мы можем передать ему любой объект, который нам нравится: временный, статический или локальный объект, который будет повторно использован для последующего вызова.
Как это бывает, объекты-токены часто являются локальными объектами, которые повторно используются при разборе.цикл, а не динамически размещаемые объекты, которые накладывают более сложный режим управления памятью.Большую часть времени к объектам токенов, переданным функциям, обращаются только к ним, но иногда их нужно сохранять.Имя функции addLocal
довольно убедительно говорит о том, что эта функция сохранит переданный объект.
В этом конкретном случае addLocal
фактически сохраняет переданный объект, но сохраняет копию.Это не может быть сделано иначе, потому что передана копия, и копия не переживет вызов.К счастью, оптимизатор почти наверняка встроит addLocal
, что позволит избежать ненужной промежуточной копии.Таким образом, использование call-by-value здесь точно сообщило читателю кода, что совершенно не нужно беспокоиться о времени жизни объекта, переданного в addLocal
.
В случае identifiersEqual
Маловероятно, что вызванная функция должна будет сохранять любой из переданных объектов, поэтому гарантия, возможно, менее важна.Но, как упомянуто выше, я бы, вероятно, написал identifiersEqual
в качестве вызова по значению, также для согласованности, надеясь, что компилятору удалось вообще избежать копирования.(Это прыжок веры, и, возможно, мое стремление к последовательности здесь является своего рода тик.)
Примечания
С очень легкими объектами и некоторыми компиляторами возможно, что вызов по значению будет генерировать лучше скомпилированный код.Например, стандартный 64-битный ABI позволяет структурам, которые помещаются в восемь байтов, передаваться в регистрах, что особенно удобно, если объект создается с единственной целью передачи его функции.Я помню, как в те дни, когда я писал в API-интерфейсы OS X GUI, небольшие геометрические объекты всегда передавались маленьким геометрическим объектам по значению и что в руководстве по программированию было примечание, объясняющее, что это было сделано для эффективности.Я не знаю, правда ли это, но я также не думаю, что эта конкретная структура достаточно легкая, чтобы ее можно было применить.Хотя это, возможно, не часто встречается, существуют другие контексты, в которых разъяснение определенным компиляторам, что адрес объекта никогда не берется, позволяет компилятору создавать лучший код.
В контексте этого вопроса достаточноОбратите внимание, что сгенерированный код для вызова по значению (вероятно) не хуже, чем вызов по ссылке.Если это действительно имеет значение для вас, вам придется проверить сгенерированный код от компилятора, который вам небезразличен.Я этого не делал.