Правила псевдонимов в 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 но это использует ключевое слово под одеялом.

Другие вопросы по тегам