Разница между 'const ref' и 'in'?
Я пытаюсь понять разницу между const ref
и in
, особенно когда дело доходит до производительности.
-
Я знаю, что in
эквивалентен const scope
, но что означает the scope storage class means that references in the parameter cannot be escaped (e.g. assigned to a global variable).
? пример кода приветствуется.
-
Как мне выбрать между const ref
и in
при реализации функции? Я знаю, что с ref
объект не копируется, потому что он ссылается, но имеет то же значение с in
?
Ответы
Ответ 1
1) класс хранения параметров scope
означает, что вам не удастся избежать ссылки на параметр. Пример:
Object glob;
struct S
{
Object o;
void foo(scope Object o)
{
this.o = o; // Not allowed! 'o' must not be escaped
glob = o; // ditto
}
}
Обратите внимание, что DMD не очень хорошо разбирается в этом. Вышеприведенный пример компилируется, но не разрешен.
scope
наиболее полезен для параметров делегата:
void foo(scope void delegate() dg)
{
/* use dg */
}
void main()
{
int i;
foo({ ++i; });
}
В приведенном выше примере для анонимной функции не требуется закрытие, даже если оно имеет значение upvalue, потому что foo
"гарантирует" (это задание компилятора...), что делегат не экранирован. В настоящее время DMD реализует эту оптимизацию.
2) Я думаю, идея состоит в том, что, когда используются как const
, так и scope
, компилятор теоретически может передавать по ссылке или по желанию, поэтому ярлык in
полезен. DMD не использует это прямо сейчас, но это удобный ярлык, тем не менее, и он имеет некоторое значение документации.
Короче говоря, in
в настоящее время не получит вам какой-либо производительности, если он не используется в делегате. ref
может дать вам некоторую производительность с большими структурами или статическими массивами. Когда ref
используется по соображениям производительности, const
часто используется для документирования (и обеспечения соблюдения) того, что ref
не используется для обновления исходного значения.
Ответ 2
-
Это не легально для параметров scope
для выхода из функции. Предполагается, что компилятор гарантирует, что никакие ссылки на эти данные не выйдут из функции. Он используется в основном с делегатами, поскольку он позволяет компилятору избегать выделения замыкания, поскольку он знает, что делегат не уйдет.
-
const ref
- const
- точно так же, как in
, но переменная передается по ссылке вместо копирования, поэтому вы избегаете копирования. Однако в отличие от С++ const ref
не работает с rvalues. Ему нужно дать lvalue. Итак, если вы объявляете параметр const ref
, это будет ограничивать то, что вы можете передать ему. Обычно вам нужно объявить переменную, чтобы перейти к ней, тогда как in
примет временную.
void func(const ref int var) {}
int a;
func(a); //legal
func(7); //illegal
Оба этих вызова будут легальными, если func
взял const
или in
. Итак, в общем, вопрос заключается не в том, следует ли использовать const ref
или in
. Вопрос в том, следует ли использовать const
или in
. И в этом случае возникает вопрос, хотите ли вы использовать scope
или нет, поскольку оба они const
. И вы используете scope
, если хотите убедиться, что никакая ссылка на переменную, которую вы передаете, не выйдет из этой функции, поэтому она обычно используется только с делегатами, но может быть полезна с классами или массивами.
Однако функция pure
для функции гарантирует, что никакие ссылки на какой-либо из ее аргументов не смогут избежать, кроме как через возвращаемое значение (поскольку функции pure
могут использовать только глобальные переменные, если они являются неизменяемыми или являются типами значений и являются константами), поэтому pure
обычно дает вам все, что вам нужно для параметров, которые являются классами и массивами. Кроме того, если тип возврата является классом или массивом, вы вообще не хотите его делать, чтобы аргументы не могли убежать, потому что вместо того, чтобы повторно использовать что-либо из этих аргументов в возвращаемом значении, функция вынужден сделать копию, которая, как правило, менее эффективна.
Итак, scope
обычно используется только с делегатами, но порой полезен для классов или массивов. В любом случае, как правило, предпочтительнее, чтобы функции были pure
, так что заботятся о большей части проблемы. Как таковой, хотя использовать in
не повредит, часто бывает мало смысла использовать in
вместо const
. И вы обычно используете только const ref
, если вы действительно хотите избежать копирования передаваемой переменной, потому что в противном случае вы можете передавать только lvalues этой функции. Вы можете перегрузить функцию таким образом, чтобы она имела версию, которая принимает const
и одну, которая принимает const ref
, но это, очевидно, приводит к дублированию кода, поэтому, если вы действительно не хотите const ref
, возможно, лучше всего использовать const
.
EDIT:
scope
еще предстоит реализовать для чего угодно, кроме делегатов (по состоянию на 2013-06-18), поэтому использование scope
или in
с чем-либо, кроме делегатов, не рекомендуется. На данный момент они вводят в заблуждение, и если/раз scope
реализовано для чего угодно, кроме делегатов, существует высокий риск того, что ваш код сломается из-за ссылок на переменные, помеченные экранированием scope
или in
.