Предотвращение наложения двух внутренних объектов
У меня есть функция подписи, похожая на это
void Mutliply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);
Внутри матричный класс имеет float* data;
это представляет m x n
компоненты. Я хотел бы сказать компилятору, что a
а также b
не создавайте псевдоним вне матрицы, чтобы он не создавал тонны хранилищ нагрузки.
Как бы я поступил так? Я знаю, что могу передать указатели на сигнатуру функции и пометить указатели с помощью __restrict
(в MSVC), но я хотел бы сохранить идиому объекта, передаваемого по ссылке, где объект содержит указатели на память.
Я тоже знаю что __restrict
не работает с объектными ссылками.
4 ответа
Написать неэкспортированный (файл-static
, private
) функция умножения, которая принимаетfloat*
аргументы, пометьте аргументы restrict
, Делать Multiply
вызвать эту функцию.
В зависимости от того, как работает оптимизатор, assert(&in1 != &out && &in2 != &out)
на вершине может сделать свое дело. Вы также можете избавиться от параметра out и доверить оптимизатору избавление от лишних копий (конечно, при условии, что это чистый параметр out). Если код является кандидатом для встраивания, компилятор может увидеть, что ничего не является псевдонимом самостоятельно. Если restrict
на самом деле не работает с ссылочными параметрами, вы можете иметь дополнительный уровень для вызова функции и передавать все три во вторую функцию, которая правильно принимает указатели. Надеюсь, что это будет сделано для вас.
Поскольку вы, кажется, знакомы с указателями __restrict, я бы использовал то, что вы знаете, но вы все еще можете обернуть его и предоставить интерфейс, используя ссылки:
void Multiply(const MatrixMN& a, const MatrixMN& b, MatrixMN& out) {
if (&a == &b || &a == &out || &b == &out) {
// indicate precondition violation however you like
assert(!"precondition violated");
abort(); // assert isn't always executed
}
else {
DoMultiply(&a, &b, &out);
}
}
void DoMultiply(MatrixMN const * __restrict a, MatrixMN const * __restrict b,
MatrixMN * __restrict out)
{
//...
}
Сделайте версию указателя "непубличной", например, поместив ее в пространство имен "details", присвоив ей внутреннюю связь (не применимо в данном конкретном случае) или присвоив ей специальное имя. Вы могли бы даже использовать локальные переменные вместо параметров и поместить тело функции в "else", но я считаю, что приведенное выше более чисто.
Как насчет макропакета, чтобы иметь __restrict
эффект непосредственно во время компиляции: (ниже псевдокод, не проверено):
#define Multiply(A,B,C) Multiply_restrict(&A, &B, &C)
Теперь промежуточный метод определяется как
inline void Multiply_restrict(const MatrixMN* __restrict pA,
const MatrixMN* __restrict pB, MatrixMN* __restrict pC)
{
Multiply_(*pA, *pB, *pC);
}
И, наконец, просто добавьте _
после вашего оригинала Multiply
:
void Mutliply_(const MatrixMN& a, const MatrixMN& b, MatrixMN& out);
Таким образом, конечный эффект будет точно таким же, как вы звоните:
Multiply(x, y, answer);