Size: a a a

2021 March 14

AG

Andrey Glebov in pro.cxx
Liber Azerate
Ну замечательно. То есть мы и доказали, что ходить по многомерному массиву как по одномерному нельзя
я именно это и доказывал, кажется у нас недопонимание вышло)
источник

LA

Liber Azerate in pro.cxx
Andrey Glebov
я именно это и доказывал, кажется у нас недопонимание вышло)
А, извиняюсь :)
источник

VS

Vlad Serebrennikov in pro.cxx
Andrey Glebov
https://eel.is/c++draft/dcl.array#9 определяет, что "многомерный массив" - это массив массивов
https://eel.is/c++draft/expr.add#4.3 говорит, что арифметика указателей за границами исходного массива не определена (не говоря о разыменовании)
строго говоря, dcl.array#9 ничего не определяет, так как не содержит нормативный текст, но очень удобный в данном споре, да
источник

LA

Liber Azerate in pro.cxx
Vlad Serebrennikov
строго говоря, dcl.array#9 ничего не определяет, так как не содержит нормативный текст, но очень удобный в данном споре, да
Ну, он и не нужен. В этом же параграфе стандарта содержатся все необходимые нормативные пункты
источник

O

Ofee in pro.cxx
Mikhail Kalugin
Вообще то имеет. Речь об эвристических оптимизациях на основе использования памяти через указатели в обход правил управления памятью определенных стандартом.
Проблема в том, что в текущей трактовке стандарта нет никакого обхода правил, определенных стандартом потому что стандарт не определяет никаких правил (или никто не смог убедительно доказать обратное)

Формально, выкинуть неиспользованные строки массива так же легально, как и выкинуть неиспользованную стековую переменную
источник

AG

Andrey Glebov in pro.cxx
ну да, не определяет, а разъясняет)
источник

MK

Mikhail Kalugin in pro.cxx
Ofee
Проблема в том, что в текущей трактовке стандарта нет никакого обхода правил, определенных стандартом потому что стандарт не определяет никаких правил (или никто не смог убедительно доказать обратное)

Формально, выкинуть неиспользованные строки массива так же легально, как и выкинуть неиспользованную стековую переменную
Вообще-то, не все так просто. Стековая переменная и часть массива разные вещи. Массив это объект. Такой же как, например, структура - развивая эту логику компилятор может выкидывать неиспользуемые поля структур, но тогда будет меняться результат sizeof для структуры, а это как минимум странно.
источник

AG

Andrey Glebov in pro.cxx
Mikhail Kalugin
Вообще-то, не все так просто. Стековая переменная и часть массива разные вещи. Массив это объект. Такой же как, например, структура - развивая эту логику компилятор может выкидывать неиспользуемые поля структур, но тогда будет меняться результат sizeof для структуры, а это как минимум странно.
https://godbolt.org/z/r894Ex
вот например, он вообще всё выкинул, но вот sizeof всё-равно правильный.
если что-то невозможно распознать при помощи валидной программы, то компилятор в полном праве это поменять
источник

O

Ofee in pro.cxx
Mikhail Kalugin
Вообще-то, не все так просто. Стековая переменная и часть массива разные вещи. Массив это объект. Такой же как, например, структура - развивая эту логику компилятор может выкидывать неиспользуемые поля структур, но тогда будет меняться результат sizeof для структуры, а это как минимум странно.
Я не могу утверждать наверняка, но могу предположить, что компилятор не может выкидывать неиспользованные поля структуры только потому что не способен статически доказать их неиспользуемость

Но что, если эта структура имеет internal linkage?
источник

AG

Andrey Glebov in pro.cxx
или ещё на этапе LTO можно так же соптимизировать
источник

MK

Mikhail Kalugin in pro.cxx
Ofee
Я не могу утверждать наверняка, но могу предположить, что компилятор не может выкидывать неиспользованные поля структуры только потому что не способен статически доказать их неиспользуемость

Но что, если эта структура имеет internal linkage?
Да, именно. Так же как с массивом. Единственное, что о нем компилятор знает наверняка это директива - выдели память от сих до сих.
источник

O

Ofee in pro.cxx
Mikhail Kalugin
Да, именно. Так же как с массивом. Единственное, что о нем компилятор знает наверняка это директива - выдели память от сих до сих.
Да, и он статически может доказать, что эта память не используется, поскольку на неё не берется даже указатель
источник

AG

Andrey Glebov in pro.cxx
Mikhail Kalugin
Да, именно. Так же как с массивом. Единственное, что о нем компилятор знает наверняка это директива - выдели память от сих до сих.
В том то и дело, что не совсем.
Он ещё знает, что это массив объектов определённого типа.
Просто линейной памяти "от сих до сих" вообще может и не существовать, особенно в constexpr контексте
источник

MK

Mikhail Kalugin in pro.cxx
Ofee
Да, и он статически может доказать, что эта память не используется, поскольку на неё не берется даже указатель
Вся - да, может. Но не часть. Потому что, как минимум существует переменная которой сопоставлен кусок памяти под массивом. Единственное что точно можно сделать, это доказать, что она вся не используется - остальное нарушение требования целостности памяти массива.
источник

O

Ofee in pro.cxx
Mikhail Kalugin
Вся - да, может. Но не часть. Потому что, как минимум существует переменная которой сопоставлен кусок памяти под массивом. Единственное что точно можно сделать, это доказать, что она вся не используется - остальное нарушение требования целостности памяти массива.
Дело в том, что согласно expr.add#4.2, имея только int* вы не можете без UB покинуть первую строку массива и перейти ко второй. И, пользуясь этим знанием, компилятор может доказать статически, что никакая арифметика над этим указателем не приводит к тому, что мы можем достигнуть элементп arr[1][0]

Соответственно, массивы arr[1], arr[2] и дальше могут справедливо считаться неиспользуемыми, ведь сам arr тоже локальный и никуда не передаётся, компилятор видит весь его лайфтайм, он может выкинуть части массива так же, как части структуры в примере выше

Но не будет. Уже под совершенно другой причине – на это слишком многие закладываются
источник

AS

Anatoly Shirokov in pro.cxx
Ofee
Дело в том, что согласно expr.add#4.2, имея только int* вы не можете без UB покинуть первую строку массива и перейти ко второй. И, пользуясь этим знанием, компилятор может доказать статически, что никакая арифметика над этим указателем не приводит к тому, что мы можем достигнуть элементп arr[1][0]

Соответственно, массивы arr[1], arr[2] и дальше могут справедливо считаться неиспользуемыми, ведь сам arr тоже локальный и никуда не передаётся, компилятор видит весь его лайфтайм, он может выкинуть части массива так же, как части структуры в примере выше

Но не будет. Уже под совершенно другой причине – на это слишком многие закладываются
Это где об этом написано?
источник

A

Anton in pro.cxx
Ofee
Дело в том, что согласно expr.add#4.2, имея только int* вы не можете без UB покинуть первую строку массива и перейти ко второй. И, пользуясь этим знанием, компилятор может доказать статически, что никакая арифметика над этим указателем не приводит к тому, что мы можем достигнуть элементп arr[1][0]

Соответственно, массивы arr[1], arr[2] и дальше могут справедливо считаться неиспользуемыми, ведь сам arr тоже локальный и никуда не передаётся, компилятор видит весь его лайфтайм, он может выкинуть части массива так же, как части структуры в примере выше

Но не будет. Уже под совершенно другой причине – на это слишком многие закладываются
там написано
When several “array of” specifications are adjacent, a multidimensional array type is created;
но нигде не написано, что такое multidimensional array, только в примере, что это массив массивов
источник
2021 March 15

MK

Mikhail Kalugin in pro.cxx
Ofee
Да, и он статически может доказать, что эта память не используется, поскольку на неё не берется даже указатель
В общем, я вижу ровно два случая (с нашим двухмерным массивом) либо декей до указателя, либо срез сокращением размерности. В первом случае компилятор не может делать никаких предположений о том что происходит - во втором, может смело выкинуть часть массива, но в коде ни что не пострадает, потому что в первом случае стандарт говорит a) существует кусок памяти, соответствующий всему массиву и б) существует указатель на первый элемент массива. Архитектура гарантирует,  что указатель может пройти по всей физически доступной памяти (и тут канонический отстрел ноги из C, но это другая история), во втором - стандарт говорит, что мы получим массив с размером равным втрой размерности и это его границы, выходить за них уже UB.
источник

AS

Anatoly Shirokov in pro.cxx
Многомерный массив занимает линейную память. Получая указатель на эту линейную память обращение к любому элементу не содержит UB в пределах N×M, включая элемент следующий за последним
источник

A

Anton in pro.cxx
Anatoly Shirokov
Многомерный массив занимает линейную память. Получая указатель на эту линейную память обращение к любому элементу не содержит UB в пределах N×M, включая элемент следующий за последним
этого тоже не написано
источник