Когда использовать ограничение, а когда нет
У меня есть общее понимание restrict
но я надеюсь уточнить некоторые тонкости. У меня есть функция, которая читает строку с нулевым символом в конце из одного буфера и записывает версию в кодировке URL в другом буфере. Функция имеет эту подпись (в настоящее время без restrict
):
char const *StringUrlEncode(char const *unencoded,
char *encoded,
char *encodedEnd);
unencoded
моя исходная строка с нулевым символом в конце Буфер назначения представлен как encoded
а также encodedEnd
, где encoded
указывает на первый char
в буфере и encodedEnd
указывает на первый символ после буфера, т.е. функция напишет char
до, но не включая местоположение, на которое указывает encodedEnd
- это ваше основное begin
/end
пара итераторов, если вы знакомы с соглашениями C++ STL.
Если я добавлю restrict
к этой функции следует применять только к первым двум параметрам:
char const *StringUrlEncode(char const *restrict unencoded,
char *restrict encoded,
char *encodedEnd);
или есть какая-то польза, которую я не понимаю, добавляя ее ко всем трем параметрам?
Я вижу, что создание входных и выходных буферов restrict
помогает компилятору знать, что они не перекрываются. Но так как последний параметр, encodedEnd
, используется только для обозначения конца буфера вывода, я думаю, что restrict
здесь не будет никакой помощи компилятору (хотя я предполагаю, что это не повредит, кроме добавления ненужного шума в объявление функции).
3 ответа
Попробуйте статью Майка Актона здесь. Ограничение является пугающим из-за последствий для производительности, связанных с его неиспользованием, и последствий его неправильного использования.
В вашем случае это звучит так, как будто вы можете смело применять ограничение ко всем трем указателям, поскольку ни один из них не имеет псевдонима в одной области памяти. Тем не менее, использование его на третьем указателе не принесет значительного выигрыша в производительности.
В этом конкретном случае не имеет значения, является ли encodedEnd ограниченным или нет; вы пообещали компилятору, что никто не будет псевдонимом и не кодировать псевдонимы, поэтому чтение и запись не будут мешать друг другу.
Настоящая причина, по которой ограничение является важной в этом случае, заключается в том, что без него компилятор не может знать, что запись через закодированный код не повлияет на чтение через незашифрованный код. Например, если
encoded == unencoded+1
тогда каждая запись в кодированную запись будет влиять на каждое последующее чтение из незашифрованного, поэтому компилятор не сможет запланировать загрузку до завершения записи. restrict обещает компилятору, что два указателя не влияют на одну и ту же память, поэтому он может планировать загрузки достаточно далеко вперед, чтобы избежать остановок конвейера.
Я думаю, что вы правы, что это не повредит. Ваш указатель цикла (назовите его p) будет равен encodedEnd в конце цикла. Но ничего не нужно делать после цикла (из p или encodedEnd), так что это не должно быть проблемой. Я не думаю, что это также поможет, потому что ничего не пишется и не читается из encodedEnd, поэтому оптимизировать нечего.
Но я согласен с тем, что первые два ограничения действительно должны помочь.