Правила псевдонимов в C++
Просто интересно, подтвердит ли кто-нибудь несколько правил наложения имен для меня.
Я знаю, что псевдонимы (то есть проблемы с загрузкой) могут привести к тому, что следующий тип кода будет неоптимальным, потому что мы не можем предположить, что x, y, z
не перекрывать
// case 1:
void plus(size_t n, double *x, double *y, double *z)
{
for (size_t i = 0; i != n; ++i)
z[i] = x[i] + y[i];
}
Я знаю, что есть ключевое слово C __restrict
это намекает компилятору, что он не должен учитывать перекрывающийся случай, и, следовательно, потенциально может генерировать лучший код:
// case 2:
void plus(size_t n, double *__restrict x, double *__restrict y, double *__restrict z)
{ // as above... }
Но как псевдонимы работают с кодом стиля C++, где мы имеем дело с объектами-контейнерами, передаваемыми по ссылке, а не с подобными C-примерами выше с необработанными указателями??
Например, я предполагаю, что были бы проблемы с наложением, если бы мы сделали следующее:
// case 3:
void plus(std::vector<double> &x, std::vector<double> &y, std::vector<double> &z)
{ // similar to above... }
И чтобы перейти к менее тривиальному примеру, имеет ли какое-то значение, если базовые типы данных в контейнерах отличаются? На уровне реализации большинство контейнеров динамически управляют хранилищем с помощью указателей, поэтому мне не ясно, как компилятор может гарантировать, что следующее не будет псевдонимом:
// case 4:
void foo(std::vector<mytype1> &x, std::vector<mytype2> &y)
{ // interwoven operations on x, y... }
Я не пытаюсь микрооптимизировать, но мне интересно, лучше ли сейчас передавать ограниченные указатели на контейнеры, а не ссылки.
РЕДАКТИРОВАТЬ: Чтобы прояснить некоторые термины, как указано: restrict
это ключевое слово C99. Есть также __restrict
а также __restrict__
в разных компиляторах, но все они делают одно и то же.
2 ответа
Согласно правилу строгого псевдонима, вы не можете создавать псевдонимы для одной и той же памяти с указателями на разные типы (кроме char*
и друзей), поэтому случай 4 может применяться только в том случае, если один из типов был char*
,
Случай 3, однако, не сильно отличается от случая 1, поскольку ссылки реализованы в виде указателей на всех известных мне компиляторах, хотя стандарт не требует этого, и реализация может предложить что-то еще.
Это совсем не относится к C++. Рассмотрим этот бит C99:
struct vector {
double* data;
size_t n;
};
void
plus(struct vector* restrict x, struct vector* restrict y, struct vector* restrict z)
{
// same deal as ever
}
Вот, restrict
очень мало нас покупает x->data
, y->data
а также z->data
являются все double*
и разрешено псевдоним. Это точно так же, как в случае 1, даже при использовании restrict.
Если бы было restrict
ключевое слово в C++ (или при использовании расширения), вероятно, лучше сделать лучшую ставку plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0])
, используя тот же plus
как в случае 2. И на самом деле это можно сделать прямо сейчас, используя интерфейс в стиле C89 без restrict
но это использует ключевое слово под одеялом.