Однако operator new определён без __declspec(restrict).
Из-за этого компилятор может произвести оптимизацию в случае использования malloc, но не может с new.
Можно проверить через флаг /Qvec-report:2
Кто знает, почему стандарт не требует возвращать указатель на не перекрывающиеся данные в 'new' в отличии от malloc ?
P.S.
Если вручную определить в своём проекте new, то можем получить существенное ускорение:
Здравствуйте, _NN_, Вы писали:
_NN>Кто знает, почему стандарт не требует возвращать указатель на не перекрывающиеся данные в 'new' в отличии от malloc ?
возможно потому, что new можно перегрузить так, чтоб он возвращал что угодно, а не только уникальный адрес...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, _NN_, Вы писали:
_NN>>Кто знает, почему стандарт не требует возвращать указатель на не перекрывающиеся данные в 'new' в отличии от malloc ?
X>возможно потому, что new можно перегрузить так, чтоб он возвращал что угодно, а не только уникальный адрес...
Низя http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : > If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
При этом http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-7 : > Furthermore, for the library allocation functions in [new.delete.single] and [new.delete.array], p0 represents the address of a block of storage disjoint from the storage for any other object accessible to the caller.
Т.е. НЕ-library функции могут возвращать, например, указатель на элемент видимого всем глобального массива.
Здравствуйте, σ, Вы писали:
σ>При этом σ>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-7 : >> Furthermore, for the library allocation functions in [new.delete.single] and [new.delete.array], p0 represents the address of a block of storage disjoint from the storage for any other object accessible to the caller.
σ>Т.е. НЕ-library функции могут возвращать, например, указатель на элемент видимого всем глобально массива.
Технически и стандартный new может в реализации также использоваться заранее выделенную область.
Хочется понять из стандарта разрешено ли в перегруженном new вернуть один и тот же адрес без вызова delete.
Лично я не вижу в этом смысла и, возможно, стоило бы указать на это как на неопределённое поведение.
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, σ, Вы писали:
σ>>При этом σ>>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-7 : >>> Furthermore, for the library allocation functions in [new.delete.single] and [new.delete.array], p0 represents the address of a block of storage disjoint from the storage for any other object accessible to the caller.
σ>>Т.е. НЕ-library функции могут возвращать, например, указатель на элемент видимого всем глобально массива. _NN>Технически и стандартный new может в реализации также использоваться заранее выделенную область.
Ключевые словосочетания: "accessible to the caller", "видимого всем".
_NN>Хочется понять из стандарта разрешено ли в перегруженном new вернуть один и тот же адрес без вызова delete.
Это же было освещено в моём сообщении http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : > If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
Здравствуйте, _NN_, Вы писали:
_NN>Если вручную определить в своём проекте new, то можем получить существенное ускорение:
Вы получите существенное ускорение если не будете вообще использовать динамическую память.
Здравствуйте, σ, Вы писали:
σ>Это же было освещено в моём сообщении σ>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : >> If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
Т.е. даже перегруженные new должны возвращать различные адреса неперекрывающихся областей, так ?
Получается нет никаких проблем пометить operator new как __declspec(restrict) и получать векторизацию.
Здравствуйте, _NN_, Вы писали:
σ>>Это же было освещено в моём сообщении σ>>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : >>> If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
_NN>Т.е. даже перегруженные new должны возвращать различные адреса неперекрывающихся областей, так ? _NN>Получается нет никаких проблем пометить operator new как __declspec(restrict) и получать векторизацию.
То, что указатели, которые возвращаются разными вызовами оператора new, должны быть различны между собой, не означает, что такой указатель не может быть получен каким-либо другим образом. Таким образом, гарантий отсутствия алиасинга нет.
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, σ, Вы писали:
σ>>Это же было освещено в моём сообщении σ>>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : >>> If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
_NN>Т.е. даже перегруженные new должны возвращать различные адреса неперекрывающихся областей, так ? _NN>Получается нет никаких проблем пометить operator new как __declspec(restrict) и получать векторизацию.
Насколько `__declspec(restrict) void*` это не нарушает, при том, что __declspec(restrict) — это расширение конкретной реализации?
Раз реализация позволяет, то почему бы и нет.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, _NN_, Вы писали:
σ>>>Это же было освещено в моём сообщении σ>>>http://eel.is/c++draft/basic.stc.dynamic.allocation#2.sentence-6 : >>>> If the request succeeds, the value returned by a replaceable allocation function is a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to a replaceable deallocation function.
_NN>>Т.е. даже перегруженные new должны возвращать различные адреса неперекрывающихся областей, так ? _NN>>Получается нет никаких проблем пометить operator new как __declspec(restrict) и получать векторизацию.
N>То, что указатели, которые возвращаются разными вызовами оператора new, должны быть различны между собой, не означает, что такой указатель не может быть получен каким-либо другим образом. Таким образом, гарантий отсутствия алиасинга нет.
ТС вроде хочет сделать свою перегрузку operator new на основе malloc, которая (в его реализации) гарантирует отсутствие алиасинга.
Как понять "гарантий отсутствия алиасинга нет"?
Здравствуйте, _NN_, Вы писали:
_NN>Если вручную определить в своём проекте new, то можем получить существенное ускорение
Я согласен, что лучше бы иметь такое свойство изначально, чем не иметь. Но не считаю, что этого достаточно.
В этом примере память используется сразу после выделения malloc'ом или new. Но как часто такая ситуация встречается в программах? Кажется, что обычно память выделяется где-то в одном месте, а используется чуть в другом. А между ними встречается всякая логика RAII, которая позволяет не утечь памяти, но при этом которая сохраняет указатель где-то в своих внутренностях (т.е. создавая возможность для alising'а где-то в другом месте). Или память может выделяться из memory-pool и возвращаться в него неоднократно. Или к ней может быть слишком сложный способ доступа (как, например, в in-place алгоритмах умножения Штрассена, где доказательство отсутствия aliasing — это предмет целой научной статьи).
То есть обычно у компилятора просто недостаточно ресурсов чтобы сохранить это свойство от момента выделения памяти, до момента её использования. Есть десяток мест, где можно эту информацию потерять, так как компилятор не сможет доказать отсутствие aliasing.
Считаю, что наивно было бы полагать, что компилятор сумеет всегда дотащить нужные атрибуты от далёкого new или malloc.
Поэтому, если нужна векторизация в критичном по производительности месте, используют другой подход: пишут restrict у переменных, а не у функций.
В примере по ссылке приведена сигнатура функции
void multiply(float * a, float * b, float * c)
Но гораздо надёжнее было бы просто написать
void multiply(float * a, float * b, float * restrict c)
То есть просто сказать, что программой и программистом гарантируется, что память под c не пересекается с a или b. И пусть компилятор оптимизирует исходя из этой гарантии. А уж каким способом выделена память под матрицы не важно: malloc это, или глобальный массив, или может вообще отображение файла в память.
То есть стоит поступать как обычно: если нужна производительность, то не ограничивать себя возможностями чистого языка, а использовать расширения самому.
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, _NN_, Вы писали:
_NN>>Если вручную определить в своём проекте new, то можем получить существенное ускорение W>Я согласен, что лучше бы иметь такое свойство изначально, чем не иметь. Но не считаю, что этого достаточно. W>В этом примере память используется сразу после выделения malloc'ом или new. Но как часто такая ситуация встречается в программах?
или std::string. или std::unique_ptr. Очень много кода, где создали и тут же работаем, или позвали фабрику, которая, если не злоупотреблять виртуальностью, тоже инлайнится (make_unique, например), поэтому после инлайна будет то же самое, что прямо в коде написал. И кода тут во всех этих объектах реально немного, компилятор вполне способен протащить информацию об алиасинге, если она есть. Но так как тут везде внутри по умолчанию используется new, то будет проблема, описанная _NN_.