static constexpr vars vs constexpr vars
От: niXman Ниоткуда https://github.com/niXman
Дата: 11.02.21 20:47
Оценка:
привет!

что-то мне кажется, что я не полностью понимаю разницу... с другой стороны, вроди разницы и нет.
вопрос к знатокам стандарта: в чем разница между?:
static constexpr int v = 33;

и
constexpr int v = 33;

в случае если это переменная-член функции.

спасибо!

зы
собственно, вопрос возник из-за того, что constexpr и так вычесляется во время компиляции, тогда имеет ли static смысл?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 11.02.2021 20:50 niXman . Предыдущая версия . Еще …
Отредактировано 11.02.2021 20:49 niXman . Предыдущая версия .
Re: static constexpr vars vs constexpr vars
От: B0FEE664  
Дата: 11.02.21 21:32
Оценка: 14 (2) +3
Здравствуйте, niXman, Вы писали:

X>вопрос к знатокам стандарта: в чем разница между?:

static constexpr int v = 33;
constexpr int v = 33;

X>в случае если это переменная-член функции.
т.е.
void f(...)
{
  static constexpr int v = 33;
  // vs
  constexpr int v = 33;

}

?

X>зы

X>собственно, вопрос возник из-за того, что constexpr и так вычесляется во время компиляции, тогда имеет ли static смысл?

Да, смысл есть. Во втором случае y будет переразмещатся на стеке при каждом вызове функции, а в первом — нет. static — это один объект на всех, сэр! А вот у просто constexpr объектов адреса должны различаться. Понятное дело, что если адрес вы не берёте, то компилятор имеет право соптимизировать, но... тут важен вопрос многопоточности... и что важнее: память или скорость...
И каждый день — без права на ошибку...
Re[2]: static constexpr vars vs constexpr vars
От: niXman Ниоткуда https://github.com/niXman
Дата: 11.02.21 21:38
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Да, смысл есть. Во втором случае y будет переразмещатся на стеке при каждом вызове функции, а в первом — нет.


не совсем понимаю. если значение вычисляется в компайл-тайм, тогда зачем вообще что-либо размещать?

BFE>static — это один объект на всех, сэр!


спасибо, кэп! =)

BFE>А вот у просто constexpr объектов адреса должны различаться. Понятное дело, что если адрес вы не берёте, то компилятор имеет право соптимизировать, но...


это, похоже, ключевое!
ведь да, если адрес не нужен — компилятор может тупо подставить результат одного и того же вычисления везде! (в идеале)

BFE>тут важен вопрос многопоточности... и что важнее: память или скорость...


но если адрес не берешь — вопроса нет?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: static constexpr vars vs constexpr vars
От: watchmaker  
Дата: 12.02.21 02:14
Оценка: 13 (2) +1
Здравствуйте, niXman, Вы писали:

X>но если адрес не берешь — вопроса нет?


Тут скорее лучше говорить об ODR-use.

BFE>>Да, смысл есть. Во втором случае y будет переразмещатся на стеке при каждом вызове функции, а в первом — нет.


X>не совсем понимаю. если значение вычисляется в компайл-тайм, тогда зачем вообще что-либо размещать?


Значение ≠ объект. То есть 33 — это значение, а int v = … — это уже переменная, которая имеет какое-то там значение и подчиняется своим правилам для переменных (и не суть важно есть там constexpr или нет).

Ещё до всяких там модных С++11 это различие повсеместно проявлялось в подобном коде:
extern void use_int(const int&);

struct A {
  static const int a = 42;
};


{
  use_int( A::a); // odr-used, программа не соберётся, если не добавить определение A::a
  use_int(+A::a); // определение A::a не требуется, просто используем значение 42
}



Но в целом для int тут не особо интересно всё получается.
А можно ведь что-то такое написать:
struct S {
    constexpr S(int q) {
        for (int& i : b) {
            i = q++;
        }
    }
    mutable int b[100]{};
};

int foo(int i) {
    /* static ? */ constexpr S s = 33;
    return s.b[i]++;
}


В таком упрощённом примере, надеюсь, наглядно видно, что хотя значение всех полей, которыми нужно инициализировать экземпляр S, и были вычислены в compile-time, но поведение функций будет совсем различное в зависимости от наличия или отсутствия static.
И что поэтому static ортогонален constexpr, и нельзя просто так из одного выводить другой, так как первый говорит об времени жизни объекта, а второй о том, что значение доступно в compile-time.
Хотя это, наверное, тоже капитанство




И да, если твой код использует сложные объекты, но известно, что поведение при этом не зависит от их адреса и уникальности, то static constexpr — хороший выбор по умолчанию. Так компилятор не будет вынужден воссоздавать их на стеке при каждом вызов функции.
А вот для простых типов вроде int, которые не ord-used, наоборот, по умолчанию лучше static не писать — ведь это позволит компилятору в некоторых случаях избавится от переменных вообще.
Re[4]: static constexpr vars vs constexpr vars
От: niXman Ниоткуда https://github.com/niXman
Дата: 12.02.21 08:00
Оценка:
Здравствуйте, watchmaker, Вы писали:

понял, спасибо!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: static constexpr vars vs constexpr vars
От: Шахтер Интернет  
Дата: 12.02.21 18:15
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>А вот для простых типов вроде int, которые не ord-used, наоборот, по умолчанию лучше static не писать — ведь это позволит компилятору в некоторых случаях избавится от переменных вообще.


Для простых типов лучше выносить определение из тела функции и писать inline constexpr

inline constexpr int ABC = 12345 ;
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: static constexpr vars vs constexpr vars
От: Videoman Россия https://hts.tv/
Дата: 14.02.21 09:41
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>
Ш>inline constexpr int ABC = 12345 ;
Ш>


А зачем тут inline ? constexpr и так всегда синоним inline.
Re[6]: static constexpr vars vs constexpr vars
От: watchmaker  
Дата: 14.02.21 18:36
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>Здравствуйте, Шахтер, Вы писали:


Ш>>Для простых типов лучше выносить определение из тела функции и писать inline constexpr


V>А зачем тут inline ? constexpr и так всегда синоним inline.


Разница есть для глобальный констант (ну и для глобальных переменных, где это применимо).

Без inline в каждом translation unit будет заведена своя уникальная копия этой константы (со внутренним связыванием), и в программу попадут они все (например, в случае odr-use, они опять же получат разные адреса). C inline будет оставлен только один экземпляр, общий для всех.




C constexpr int эффект обычно не очень сильный — ну бинарник растёт чуть-чуть в размере.
Но если в заголовочном файле определить глобальную константу (без constexpr и без inline) с каким-нибудь нетривиальным конструктором (например, const std::string global_foo = "foo";), и включить этот заголовочный файл в остальные исходники проекта, то после сборки программа так же получит десятки и сотни копий этой константы (по одной из каждого TU), которые будут при старте программы медленно создаваться и кратно тратить память.
Re[7]: static constexpr vars vs constexpr vars
От: Videoman Россия https://hts.tv/
Дата: 14.02.21 18:57
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Без inline в каждом translation unit будет заведена своя уникальная копия этой константы (со внутренним связыванием), и в программу попадут они все (например, в случае odr-use, они опять же получат разные адреса). C inline будет оставлен только один экземпляр, общий для всех.


Как же они опять все правила запутали с этим constexpr. А функции, как я понял, возвращающие constexpr уже неявно inline и ODR не нарушается. Это так?

При этом static переменные члены класса тоже неявно inline. Зачем опять все так запутали?

W>Но если в заголовочном файле определить глобальную константу (без constexpr и без inline) с каким-нибудь нетривиальным конструктором (например, const std::string global_foo = "foo";), и включить этот заголовочный файл в остальные исходники проекта, то после сборки программа так же получит десятки и сотни копий этой константы (по одной из каждого TU), которые будут при старте программы медленно создаваться и кратно тратить память.


Это всегда так было. Тут constexpr особо нового ничего не вносит.
Отредактировано 14.02.2021 19:12 Videoman . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.