#include <iostream>
class MyClass {
public:
const int value;
constexpr MyClass(int v) : value(v) {}
};
int main() {
const MyClass* obj1 = new MyClass(5);
const MyClass* obj2 = new MyClass(5);
std::cout << "Address of obj1: " <<static_cast<const void*>(obj1) << std::endl;
std::cout << "Address of obj2: " << static_cast<const void*>(obj2) << std::endl;
return 0;
}
Имеем constexpr в конструкторе и const при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз?
Вроде бы мелочь, а открываются колоссальные возможности по оптимизации — как то если уже обработали такой же (с таким же адресом объект) — то можно повторно не обрабатывать а выдать из кеша. Узнал что в Dart так сделали и какие возможности открыла такая, казалось бы, мелочь — и до сих пор не могу отойти от этой мысли — насколько концепция поменялась.
Или как-то можно это сделать хитроумными способами?
S>Имеем constexpr в конструкторе и constexpr при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз?
Если пользователь создал два константных объекта, значит ему это нужно.
S>Вроде бы мелочь, а открываются колоссальные возможности по оптимизации — как то если уже обработали такой же (с таким же адресом объект) — то можно повторно не обрабатывать а выдать из кеша. Узнал что в Dart так сделали и какие возможности открыла такая, казалось бы, мелочь — и до сих пор не могу отойти от этой мысли — насколько концепция поменялась.
S>Или как-то можно это сделать хитроумными способами?
А для этого существует "синглетон"!
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Shmj, Вы писали:
S>Или как-то можно это сделать хитроумными способами?
Скоро узнаешь о концепции COW, восхитишься, начнёшь применять. Потом поймаешь тормоза в многопоточке, разберёшься и откажешься. И начнёшь использовать всё по месту и по необходимости.
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Если пользователь создал два константных объекта, значит ему это нужно.
constexpr зачем может быть нужно, хотя бы один сценарий.
SVZ>А для этого существует "синглетон"!
Дык концепция константности нужна — инициализация разными значениями, но без возможности потом изменить что-либо во внутрянке. Если это сделать, то открывается совершенно подход к оптимизации.
Здравствуйте, Shmj, Вы писали:
SVZ>>Если пользователь создал два константных объекта, значит ему это нужно.
S>constexpr зачем может быть нужно, хотя бы один сценарий.
Адреса объектов иногда используются в качестве ключа в коллекциях.
Бывают реализации защиты ПО от взлома/ревёрсинга. Тут _желательно_, чтобы одни и те же объекты располагались в разных частях памяти.
Может потребоваться несколько объектов одного типа с разной инициализацией. А если внутри объекта будет нетривиальная логика, то сомневаюсь, что компилятор будет в состоянии определить, являются ли разные инстансы одним объектом или разными.
Для того и программист, чтобы знать это наверняка и сообщить компилятору.
А если программист — "не бог весть" , то не надо писать на С++, для таких есть питон.
SVZ>>А для этого существует "синглетон"!
S>Дык концепция константности нужна — инициализация разными значениями, но без возможности потом изменить что-либо во внутрянке. Если это сделать, то открывается совершенно подход к оптимизации.
На здоровье!
Но если тебе нужен _один_ объект, то для этого существует паттерн "синглетон".
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Shmj, Вы писали:
S>Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>>Если пользователь создал два константных объекта, значит ему это нужно.
S>constexpr зачем может быть нужно, хотя бы один сценарий.
Указатель на глобальный объект (адрес объекта) часто используется как уникальный идентификатор.
Для этого есть гарантия, что разные, одновременно существующие экземпляры объектов, имеют различные адреса.
struct house
{
int number_of_rooms;
};
constexpr house my_house{ 3 };
constexpr house my_sister_house{ 3 };
constexpr house parent_house{ 5 };
constexpr house grand_parent_house{ 4 };
const std::map< std::pair< const house *, const house * >, int > distances={
{{&my_house, &my_sister_house}, 10},
{{&my_house, &parent_house}, 12},
{{&my_house, &my_sister_house}, 20},
{{&my_house, &grand_parent_house}, 42},
{{&my_sister_house, &parent_house}, 12},
{{&my_sister_house, &my_sister_house}, 20},
{{&my_sister_house, &grand_parent_house}, 42},
};
Здравствуйте, Shmj, Вы писали:
S>— для вас очевидно что str1 и str2 имеют единый адрес? Разумно?
Совершенно не очевидно, никаким стандартом не гарантировано и оставлено на усмотрение компилятора.
А если ты две идентичные строки объявишь в разных единицах трансляции, то это вообще вопрос к линкеру, сводить их или нет (и что-то мне подсказывает, что скорее всего, не сведёт).
S>Имеем constexpr в конструкторе и constexpr при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз?
Пальцем не покажу, но насколько я помню, стандарты C/C++ гарантируют, что каждый динамически выделенный объект получит уникальный адрес (среди прочих живых в данный момент динамически выделенных объектов). Даже если сам объект занимает 0 байт.
S>Узнал что в Dart так сделали и какие возможности открыла такая, казалось бы, мелочь — и до сих пор не могу отойти от этой мысли — насколько концепция поменялась.
В Snobol-4, языке из 60-х, совпадающие строки размещались по совпадающим адресам. Я рад, что в языке Dart из 21-го века не забывают старые традиции
Здравствуйте, Nuzhny, Вы писали:
N>Скоро узнаешь о концепции COW, восхитишься, начнёшь применять. Потом поймаешь тормоза в многопоточке, разберёшься и откажешься. И начнёшь использовать всё по месту и по необходимости.
Я тоже не сразу понял концепцию — как-то не задумывался что это может иметь такие последствия.
Тут же не только в том дело, что объект не расходует память и это гарантированно. Важно что можно утверждать что объект не изменился и можно не вызывать повторно его методы.
Вы можете типа добавить поле — объект не будет меняться, я так думаю. Но это не то — нет проверки компилятором.
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Адреса объектов иногда используются в качестве ключа в коллекциях.
Можно же не constexpr использовать.
SVZ>На здоровье! SVZ>Но если тебе нужен _один_ объект, то для этого существует паттерн "синглетон".
Нет, вы тоже не поняли идею. Не удивлен, у меня 2 месяца ушло, чтобы это оценить.
Дело не в том что объект один. Объекты экономят память — проверяются данные constexpr и если все то же самое уже есть в памяти — нет нужны создавать. Но это еще цветочки. Ягодки — это все приводит к новой концепции оптимизаций — теперь при вызове методов таких объектов имеем 100% гарантию что метод вернет все то же самое, по этому метод можно не вызывать. Небольшие оговорки есть, конечно.
Здравствуйте, Chorkov, Вы писали:
C>Указатель на глобальный объект (адрес объекта) часто используется как уникальный идентификатор. C>Для этого есть гарантия, что разные, одновременно существующие экземпляры объектов, имеют различные адреса.
Можно было инициализировать разными данными (номер добавить) — тогда и адреса будут разные.
Здравствуйте, Shmj, Вы писали:
SVZ>>Адреса объектов иногда используются в качестве ключа в коллекциях.
S>Можно же не constexpr использовать.
У constexpr есть конкретное назначение. Не надо его усложнять.
SVZ>>Но если тебе нужен _один_ объект, то для этого существует паттерн "синглетон".
S>Нет, вы тоже не поняли идею. Не удивлен, у меня 2 месяца ушло, чтобы это оценить.
Да нечего тут понимать. Ты хочешь, чтобы компилятор (автоматически) делал то, что всегда делали руками (осмысленно).
S>Дело не в том что объект один. Объекты экономят память — проверяются данные constexpr и если все то же самое уже есть в памяти — нет нужны создавать. Но это еще цветочки. Ягодки — это все приводит к новой концепции оптимизаций — теперь при вызове методов таких объектов имеем 100% гарантию что метод вернет все то же самое, по этому метод можно не вызывать. Небольшие оговорки есть, конечно.
Очнись! Этой "новой" концепции уже лет 25, если не больше. Только реализовывали руками, ибо нечего там компилятору делать.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Pzz, Вы писали:
Pzz>Совершенно не очевидно, никаким стандартом не гарантировано и оставлено на усмотрение компилятора.
Хорошо что хотя бы для строк иногда работает.
Pzz>В Snobol-4, языке из 60-х, совпадающие строки размещались по совпадающим адресам. Я рад, что в языке Dart из 21-го века не забывают старые традиции
В Dart работает не со строками — а со всеми константными объектами.
Я тоже 2 месяца не понимал насколько это важно и как изменяет концепцию оптимизации.
Здравствуйте, Pzz, Вы писали: Pzz>А если ты две идентичные строки объявишь в разных единицах трансляции, то это вообще вопрос к линкеру, сводить их или нет (и что-то мне подсказывает, что скорее всего, не сведёт).
Аж любопытно стало. Проверил.
a.c
#include <stdio.h>
void b (void);
int main (int, char**)
{
const char* a = "Hello";
printf ("a.c: %s\n", a);
b ();
return 0;
}
b.c
#include <stdio.h>
void b (void)
{
const char* c = "Hello";
printf ("b.c: %s\n", c);
}
# gcc -v
...
gcc version 12.2.0 (Debian 12.2.0-14)
Здравствуйте, Shmj, Вы писали:
S>Тут же не только в том дело, что объект не расходует память и это гарантированно. Важно что можно утверждать что объект не изменился и можно не вызывать повторно его методы.
А если методы объекта имеют побочные эффекты, не связанные с объектом?
Здравствуйте, Pzz, Вы писали:
Pzz>А если методы объекта имеют побочные эффекты, не связанные с объектом?
Если константный класс (конструктор с const) — то ограничения не касаются тела методов, к сожалению Но просто для себя знайте что такие методы не должны иметь т.н. побочных эффектов. Если допустили побочный эффект — ССЗБ, не нужно было делать const-конструктор.
Сделали так, чтобы все-таки можно было работать с не-константными внешними объектами, иначе будет очень узкая сфера применения — а сейчас используется на полную. Т.е. просто для себя знать — не делать const, если методы не чистые. Компилятор пока не проверяет.
Здравствуйте, Shmj, Вы писали:
Pzz>>А если методы объекта имеют побочные эффекты, не связанные с объектом?
S>Если константный класс (конструктор с const) — то ограничения не касаются тела методов, к сожалению Но просто для себя знайте что такие методы не должны иметь т.н. побочных эффектов. Если допустили побочный эффект — ССЗБ, не нужно было делать const-конструктор.
"Просто для себя знайте..." — это в спецификации языка так написано и проверяется компилятором, или негласная договорённость среди посвященных?
S>Сделали так, чтобы все-таки можно было работать с не-константными внешними объектами, иначе будет очень узкая сфера применения — а сейчас используется на полную. Т.е. просто для себя знать — не делать const, если методы не чистые. Компилятор пока не проверяет.
Мне что-то кажется, что после Go как-то стыдно делать языки, не обеспечивающие обратной совместимости (в том смысле, что более новая версия компилятора может не съесть соответствующий спецификации языка код, который ела более старая версия компилятора). Неужели Dart — исключение?
Здравствуйте, Pzz, Вы писали:
S>>Если константный класс (конструктор с const) — то ограничения не касаются тела методов, к сожалению Но просто для себя знайте что такие методы не должны иметь т.н. побочных эффектов. Если допустили побочный эффект — ССЗБ, не нужно было делать const-конструктор.
Pzz>"Просто для себя знайте..." — это в спецификации языка так написано и проверяется компилятором, или негласная договорённость среди посвященных?
Компилятор гарантирует что объекты с константные одинаковыми данными — будут иметь один и тот же адрес. А остальное — построение дерева — это уже не язык а отдельная мощная библиотека. Так вот — если передаете const — оно не будет вызывать build второй раз. Хотите без оптимизации — делайте без const.
Здравствуйте, Shmj, Вы писали:
S>— для вас очевидно что str1 и str2 имеют единый адрес? Разумно?
Нет, неочевидно. Во-первых, никто не обещал что компилятор будет пытаться запоминать одинаковые литералы. Во-вторых, если строки объявлены в разных сурсах, то это ещё более неочевидно.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте