#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% скорости в никому не нужном синтетическом тесте
, что адреса у str1 и str2 все же разные, давай теперь разберёмся, что же у них одинаковое и почему.
Как не трудно увидеть из объявления str1 и str2 — это указатели. И как и все указатели, они обладают присущей всем указателям двойственностью — есть собственно объект указателя и у этого указателя есть значение — адрес какого-то объекта, располагающегося где-то в памяти. Так вот, в случае str1 и str2 — это два разных объекта с разными адресами, но с одинаковыми значениями. А почему же значения этих указателей оказались одинаковыми? Чтобы ответить на этот вопрос, нужно заглянуть в стандарт языка С++, в раздел String literals:
9 Evaluating a string-literal results in a string literal object with static storage duration ([basic.stc]).
[Note 4: String literal objects are potentially non-unique ([intro.object]). Whether successive evaluations of a string-literal yield the same or a different object is unspecified.
— end note]
Ключевое я выделил. Как видишь, стандарт не запрещает разным строковым литералам быть ассоциированными с одним и тем же объектом, но и не гарантирует, что это будет именно так. То есть, компилятор может решать этот вопрос по своему усмотрению. Так что, то, что они совпали в данном конкректном случае, можешь считать счастливой случайностью.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
Pzz>>"Просто для себя знайте..." — это в спецификации языка так написано и проверяется компилятором, или негласная договорённость среди посвященных?
S>Компилятор гарантирует что объекты с константные одинаковыми данными — будут иметь один и тот же адрес. А остальное — построение дерева — это уже не язык а отдельная мощная библиотека. Так вот — если передаете const — оно не будет вызывать build второй раз. Хотите без оптимизации — делайте без const.
При чем тут оптимизация?
Ты сказал, что компилятор может не вызывать метод объекта, если у него уже есть такой же объект (или если он уже вызывал такой метод). У меня это вызывает очень большие сомнения.
Здравствуйте, rg45, Вы писали:
R>Как не трудно увидеть из объявления str1 и str2 — это указатели. И как и все указатели, они обладают присущей всем указателям двойственностью — есть собственно объект указателя и у этого указателя есть значение — адрес какого-то объекта, располагающегося где-то в памяти. Так вот, в случае str1 и str2 — это два разных объекта с разными адресами, но с одинаковыми значениями. А почему же значения этих указателей оказались одинаковыми? Чтобы ответить на этот вопрос, нужно заглянуть в стандарт языка С++, в раздел String literals:
Это и так понятно.
R>Ключевое я выделил. Как видишь, никто нам не гарантирует, что значения str1 и str2 будут совпадать. То, что они совпали в данном случае, можешь считать счастливой случайностью.
Не случайность а оптимизация. Но подобные оптимизации в C++ возможны только для строк, для более сложных constexpr — так же могли бы сделать в теории, но пока не смогли на практике.
Здравствуйте, Pzz, Вы писали:
Pzz>При чем тут оптимизация? Pzz>Ты сказал, что компилятор может не вызывать метод объекта, если у него уже есть такой же объект (или если он уже вызывал такой метод). У меня это вызывает очень большие сомнения.
Не компилятор — а основной фреймворк — Flutter — проводит такую оптимизацию — при перестроении дерева проверят изменился ли адрес — если не изменился — то ветку не перестраивает а оставляет все как было. Const — не изменяются никогда, даже будут добавлены заново (новые оъекты) с теми же значениями.
Здравствуйте, Shmj, Вы писали:
S>Не случайность а оптимизация. Но подобные оптимизации в C++ возможны только для строк, для более сложных constexpr — так же могли бы сделать в теории, но пока не смогли на практике.
Откуда у тебя уверенность, что подобные оптимизации невозможны для других типов? Компилятор может применять любые оптимизации, если это не меняет видимого поведения программы — вплоть до того, что вообще не создавать каких-то объектов, которые фигурируют в исходном тексте программы. Но только к твоему случаю это не относится — ты ведь выводишь на печать адреса объектов, а они обязаны быть разными. Соответственно компилятор не может применить подобную оптимизацию в данном случае. Своего рода эффект наблюдателя.
P.S. Тьфу, блин, всё-таки, втянул ты меня в свою болтологию.
P.P.S. И кстати, в твоём примере компмилер запросто может вывести на экран два фейковых адреса, где ПРЕДПОЛОЖИТЕЛЬНО могли БЫ быть созданы твои объекты, а создание самих объектов проскипать. Опять же, если это не меняет видимого поведения программы. И обнаружить ты это можешь только заглянув в объектный код.
Это я написал, не подумав. Не может он поскипать создание объектов, потому что не видит, каким образом эти адреса используются в basic_ostream::opeartor<<.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Откуда у тебя уверенность, что подобные оптимизации невозможны для других типов?
Вот если бы была гарантия хотя бы для constexpr с одинаковыми данными... Не так уж сложно добавить словарик и в момент компиляции не создавать лишнего.
, понял как лучше донести.
R>А я было уже подумал: "вот молодец, не засирает профильный форум". Но не в этот раз, походу.
Rg45!
Ну ты блин, оптимист!
"Не засирает..." Ага! Щазззз!!!
Всё ж просто: ты когда читал пост? Ага в 21::25...
N>Скоро узнаешь о концепции COW, восхитишься, начнёшь применять. Потом поймаешь тормоза в многопоточке, разберёшься и откажешься. И начнёшь использовать всё по месту и по необходимости.
S>....как-то не задумывался что это может иметь такие последствия.
Такое ощущение, что наш достославный Шмыджик, пишет код только на бумажке. И, кстати, отлаживает его также... На бумажке...
Тогда всё сходится. Хулио там задумываться?
Здравствуйте, Pzz, Вы писали:
Pzz>А если ты две идентичные строки объявишь в разных единицах трансляции, то это вообще вопрос к линкеру, сводить их или нет (и что-то мне подсказывает, что скорее всего, не сведёт).
В ELF отдельный флаг секции, 'S' для GNU as, есть для объединения NUL-terminated строк. Линкеры его отрабатывают.
Вот для других данных уже не так просто.
Я бы не удивился, если бы где-то делали подсекции с именами согласно хэшу содержимого
C>Такое ощущение, что наш достославный Шмыджик, пишет код только на бумажке. И, кстати, отлаживает его также... На бумажке... C>Тогда всё сходится. Хулио там задумываться?
Хе-хе , Когда-то давно, когда машинное время выделялось всего два часа в неделю, и надо было успеть ввести код, проверить, получить результат и отчитаться, то программировали именно на бумажке. И задумываться надо было вдвойне.
Это сейчас можно педалить любую дичь — тебя ide поправит ещё до вызова компилятора.
N.B. ёлы-палы, какой я старый...
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Shmj, Вы писали:
S>Можно было инициализировать разными данными (номер добавить) — тогда и адреса будут разные.
С уникальными номерами плохо: придётся вручную вести централизованный реестр использованных номеров.
+ Проблемы с библиотеками сторонних поставщиков, плагины (.dll), нумерация в разных единицах трансляции...
Уникальные адреса — проще.
C>>Такое ощущение, что наш достославный Шмыджик, пишет код только на бумажке. И, кстати, отлаживает его также... На бумажке... C>>Тогда всё сходится. Хулио там задумываться?
SVZ>Хе-хе , Когда-то давно, когда машинное время выделялось всего два часа в неделю, и надо было успеть ввести код, проверить, получить результат и отчитаться, то программировали именно на бумажке. И задумываться надо было вдвойне. SVZ>Это сейчас можно педалить любую дичь — тебя ide поправит ещё до вызова компилятора.
SVZ>N.B. ёлы-палы, какой я старый...
Дык и я сложные задачи всегда начинаю на бумажке. А только потом тесты ваять, наброски. А уж потом, только затем...
И дело тут не в двух часах машинного времени.
Просто-напросто такой подход позволяет не впадать в популярнейшую концепцию разработки "хиракс, хиракс ‒ и в продакшен".
Больше раздолья для анализа, ну и погонять в тестовом коде, чтобы прочуйствовать нюансы.
Здравствуйте, Shmj, Вы писали:
S>Тут же не только в том дело, что объект не расходует память и это гарантированно. Важно что можно утверждать что объект не изменился и можно не вызывать повторно его методы.
Плюсовый компилятор и так это делает, если может доказать. А верить программисту на слово, который "мамой клянусь, объект константный, метод вернёт то же самое" компилятору никак нельзя
Здравствуйте, Shmj, Вы писали:
S>Сделали так, чтобы все-таки можно было работать с не-константными внешними объектами, иначе будет очень узкая сфера применения — а сейчас используется на полную. Т.е. просто для себя знать — не делать const, если методы не чистые. Компилятор пока не проверяет.
Здравствуйте, Shmj, Вы писали:
S>Не компилятор — а основной фреймворк — Flutter — проводит такую оптимизацию — при перестроении дерева проверят изменился ли адрес — если не изменился — то ветку не перестраивает а оставляет все как было. Const — не изменяются никогда, даже будут добавлены заново (новые оъекты) с теми же значениями.
Подожди, ты говорил о языке (т.е. компилятор), а теперь говоришь, что это делает библиотека. Что мешает тебе в твоей библиотеке на плюсах заводить поле с флагом, и делать всё то же, что делает библиотека на дарте?
Здравствуйте, пффф, Вы писали:
S>>Не компилятор — а основной фреймворк — Flutter — проводит такую оптимизацию — при перестроении дерева проверят изменился ли адрес — если не изменился — то ветку не перестраивает а оставляет все как было. Const — не изменяются никогда, даже будут добавлены заново (новые оъекты) с теми же значениями.
П>Подожди, ты говорил о языке (т.е. компилятор), а теперь говоришь, что это делает библиотека. Что мешает тебе в твоей библиотеке на плюсах заводить поле с флагом, и делать всё то же, что делает библиотека на дарте?
Не библиотека а фреймворк. Язык обеспечивает идентичность — размещение по одному адресу. А фреймворк уже использует этот факт для супер-оптимизаций.
Здравствуйте, Shmj, Вы писали:
S>Если константный класс (конструктор с const) — то ограничения не касаются тела методов, к сожалению Но просто для себя знайте что такие методы не должны иметь т.н. побочных эффектов. Если допустили побочный эффект — ССЗБ, не нужно было делать const-конструктор.
S>Сделали так, чтобы все-таки можно было работать с не-константными внешними объектами, иначе будет очень узкая сфера применения — а сейчас используется на полную. Т.е. просто для себя знать — не делать const, если методы не чистые. Компилятор пока не проверяет.
Вот ты непрошибаемый. Тебе не приходило в голову, что, если б не твои операции взятия адресов, то компилятор мог бы вообще не создавать никаких объектов? Вот тебе пример, обрати внимание на созданный машинный код:
Когда ты выводишь на печать адреса, компилятор не видит, что происходит с этими адресами внутри РАН-ТАЙМОВОГО std::basic_ostream<char, std::char_traits<char> >::operator<<(int). Поэтому он вынужден честно сгенерировать два РАНТАЙМОВЫХ объекта.
То есть, ты возмущаешься тому, что создаётся два объекта вместо одного в то время, когда вообще никаких объектов не создаётся. И всё из-за твоих невежественных попыток определить количество компайл-тайм объектов, через взятие их адресов! Капец, блин, целую теорию построил на своём невежестве.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, пффф, Вы писали:
S>>Тут же не только в том дело, что объект не расходует память и это гарантированно. Важно что можно утверждать что объект не изменился и можно не вызывать повторно его методы. П>Плюсовый компилятор и так это делает, если может доказать. А верить программисту на слово, который "мамой клянусь, объект константный, метод вернёт то же самое" компилятору никак нельзя
Чуть подправил код:
#include <iostream>
class MyClass {
public:
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;
}
— тут есть гарантия что не нужно выделять память по 100 раз?
Здравствуйте, rg45, Вы писали:
R>Вот ты непрошибаемый. Тебе не приходило в голову, что, если б не твои операции взятия адресов, то компилятор мог бы вообще не создавать никаких объектов? Вот тебе пример, обрати внимание на созданный машинный код:
R>https://godbolt.org/z/nrjM1rhMa
Ну вот этого я и ждал, лучше опозориться и узнать что-то полезное, чем с гордостью сохранять невежество.
Ты прикалываешься, что ли? Ты явно создаешь два объекта в динамической памяти, а компилятор должен вместо двух объектов создать один? С какого перепуга?
Я уже молчу, что за такой код нужно подсрачниками гнать из профессии.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Ты прикалываешься, что ли? Ты явно создаешь два объекта в динамической памяти, а компилятор должен вместо двух объектов создать один? С какого перепуга?
Если объекты константные, не подлежат изменению, абсолютно одинаковые — то зачем два раза выделять память?
R>Я уже молчу, что за такой код нужно подсрачниками гнать из профессии.
А как еще продемонстрировать проблему? Смартпоинтеры будут рабоать так же.
Если конструируете UI-дерево, добавляете в список одинаковые const-объекты — они постоянно будут создаваться заново.
Здравствуйте, Shmj, Вы писали:
S>Если объекты константные, не подлежат изменению, абсолютно одинаковые — то зачем два раза выделять память?
Во-первых, нет здесь никаких константных объектов. Ты ссылаешься на них как на константные, но создаются они как неконстантные. Снятие константности через const_cast и использование этих объектов как неконстантных вполне правомерно.
S>А как еще продемонстрировать проблему? Смартпоинтеры будут рабоать так же.
Так если ты не можешь продемонстрировать проблему, может, и проблемы никакой нет?
S>Если конструируете UI-дерево, добавляете в список одинаковые const-объекты — они постоянно будут создаваться заново.
У тебя есть все возможности для того, чтобы решить эту проблему собственными силами.
Вообще, ты подбешивать уже начинаешь. Иди учи матчасть.
--
Справедливость выше закона. А человечность выше справедливости.
S>- тут есть гарантия что не нужно выделять память по 100 раз?
Зачем два раза создавать объект в куче? Твои гениальные предложения сводятся к тому, что у вас на дарте думать не принято, и в компилятор в попытках исправить то, что вы там наколбасите, придумали эту странную оптимизацию На плюсах разработчик обычно достаточно опытный, и продумывает архитектуру, и у него одинаковых неизменяемых объектов просто не будет
Здравствуйте, rg45, Вы писали:
R>Во-первых, нет здесь никаких константных объектов. Ты ссылаешься на них как на константные, но создаются они как неконстантные. Снятие константности через const_cast и использование этих объектов как неконстантных вполне правомерно.
Хорошо, покажите как создавать константные объекты. Может я не правильно создаю?
R>У тебя есть все возможности для того, чтобы решить эту проблему собственными силами.
Для этого нужно все одинаковое контролировать вручную.
Здравствуйте, Marty, Вы писали:
S>>Если конструируете UI-дерево, M>Задача весьма редкая
В Flutter — основной фреймворк Dart — это постоянно далается. Причем посмотрите как — вроде бы императивно, но выглядит как JSON — практически декларативно, но с возможностью при необходимости спуститься до императивности.
Убеждение что UI лучше описывать на XML а не на ЯП — только лишь вера, ни на чем не основанная.
S>>добавляете в список одинаковые const-объекты — M>Не добавляй. Делай копию shared_ptr'а. Лучше продумывай архитектуру.
Вручную слишком сложно контролировать.
M>Это не слишком дорого. А сколько будет времени тратится на проверку, что такой объект уже создан?
Так по словарю во время компиляции проверить — не долго. Даже 1 млн. объектов будут за секунду в словаре найдены.
Здравствуйте, Shmj, Вы писали:
S>Хорошо, покажите как создавать константные объекты. Может я не правильно создаю?
Для начала, мне бы хотелось бы убедиться, что ты правильно понимаешь этот термин. То, что ты лепишь к конструктору "constexpr", а потом создаёшь объект в динамической памяти, указывает на то, что у тебя в голове полная каша. Я тебе уже сказал: иди учи матчасть.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Marty, Вы писали:
M>Зачем два раза создавать объект в куче? Твои гениальные предложения сводятся к тому, что у вас на дарте думать не принято, и в компилятор в попытках исправить то, что вы там наколбасите, придумали эту странную оптимизацию На плюсах разработчик обычно достаточно опытный, и продумывает архитектуру, и у него одинаковых неизменяемых объектов просто не будет
Два раза создавать не нужно — достаточно одного раза, т.к. объект не изменяется и всем хватит ссылки на одно и то же.
Здравствуйте, rg45, Вы писали:
R>Для начала, мне бы хотелось бы убедиться, что ты правильно понимаешь этот термин. То, что ты лепишь к конструктору "constexpr", а потом создаёшь объект в динамической памяти, указывает на то, что у тебя в голове полная каша. Я тебе уже сказал: иди учи матчасть.
constexpr к конструктору — а как мне еще обозначить что не нужно 100 раз выделять память и хватит одного экземпляра на всю программу для всех. const — конструкторов нет. Поля сделал const. Что еще нужно?
Здравствуйте, Shmj, Вы писали:
S>constexpr к конструктору — а как мне еще обозначить что не нужно 100 раз выделять память и хватит одного экземпляра на всю программу для всех. const — конструкторов нет. Поля сделал const. Что еще нужно?
Ещё нужно на монитор подышать и посидеть на клавиатуре.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>constexpr к конструктору — а как мне еще обозначить что не нужно 100 раз выделять память и хватит одного экземпляра на всю программу для всех. const — конструкторов нет. Поля сделал const. Что еще нужно?
Про паттерны проектирования слышал, что-нибудь? Если нет, то это время пришло.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
R>>У тебя есть все возможности для того, чтобы решить эту проблему собственными силами.
S>Для этого нужно все одинаковое контролировать вручную.
На С++ и так постоянно гонят, представляю, что начнется, если компиляторы начнут ещё делать то, о чём их не просят.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
S>>constexpr к конструктору — а как мне еще обозначить что не нужно 100 раз выделять память и хватит одного экземпляра на всю программу для всех. const — конструкторов нет. Поля сделал const. Что еще нужно?
R>Про паттерны проектирования слышал, что-нибудь? Если нет, то это время пришло.
Никаким паттерном ты этого не решишь. Можно создать объект и после этого проверить если уже такой существует в словаре — то не включать в словарь повторно. Но для этого придется сначала создать и выполнять проверки на этапе выполнения.
Если бы в C++ была возможность создать константный объект + компилятор бы понимал что нет смысла дублировать их — было бы куль.
Здравствуйте, Shmj, Вы писали:
S>Никаким паттерном ты этого не решишь. Можно создать объект и после этого проверить если уже такой существует в словаре — то не включать в словарь повторно. Но для этого придется сначала создать и выполнять проверки на этапе выполнения.
Паттерны проектирования — это про подходы к проектированию, а не про этапы выполнения или компиляции. Многие из распространенных паттернов имеют решения как на этапе выполнения, так и на этапе компиляции. И ты бы это знал, если меньше словоблудил, а больше уделял внимания изучению языка и практике.
Да и стремление всё на свете впихнуть в компайл-тайм нездоровое само по себе. Попахивает преждевременной оптимизацией.
S>Если бы в C++ была возможность создать константный объект + компилятор бы понимал что нет смысла дублировать их — было бы куль.
А если бы у бабушки была борода, то она была бы дедушкой.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>Имеем constexpr в конструкторе и const при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз?
test.java
const start = new Date();
// какие то вычисления...const end = new Date();
System.out.println("Elapsed: " + (end - start)); // Упс ((
Здравствуйте, sergeya, Вы писали:
S>>Имеем constexpr в конструкторе и const при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз?
S>test.java
error: illegal start of expression
const start = new Date();
что то похожее на constexpr есть в выражениях разрешенных в значениях аннотаций и там нельзя new Date() конечно
Здравствуйте, Shmj, Вы писали:
S>Никаким паттерном ты этого не решишь. Можно создать объект и после этого проверить если уже такой существует в словаре — то не включать в словарь повторно. Но для этого придется сначала создать и выполнять проверки на этапе выполнения.
Так уж и быть. Вот тебе в качестве иллюстрации идеи:
Обрати внимание, совсем не обязательно объявлять конструктор constexpr. Этот конструктор вообще можно выкинуть, всё будет работать и без него.
Повторюсь, это лишь иллюстрация идеи — самая примитивная, самая "лобовая". Это идею можно обыграть на сотни вариантов — с многопоточностью, с управляетмым временем жизни, со смартпоинтерами, без смарт-поинтеров, можно использовать оберточные классы и функции и т.д. и т.п. — в зависимости от конкретных условий применения.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, пффф, Вы писали:
S>>Хорошо, покажите как создавать константные объекты. Может я не правильно создаю?
П>Никак. С любого объекта можно снять константность.
На самом деле, можно создать константный объект и в динамической памяти:
const MyClass* obj1 = new const MyClass(5);
Снятие константности с такого объекта и использование его как неконстантного порождает неопределённое поведение.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
П>>Никак. С любого объекта можно снять константность.
R>На самом деле, можно создать константный объект и в динамической памяти:
R>
R>const MyClass* obj1 = new const MyClass(5);
R>
Можно. Но зачем?
R>Снятие константности с такого объекта и использование его как неконстантного порождает неопределённое поведение.
Хм. Не знал. Впрочем, никогда на куче константные объекты не создавал. А почему тут UB?
Здравствуйте, пффф, Вы писали:
П>Хм. Не знал. Впрочем, никогда на куче константные объекты не создавал. А почему тут UB?
Ну это общее требование стандарта к константным объектам, независимо от области их обитания. Наверное, оставляют разработчикам компиляторов больше возможностей для оптимизаций.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
П>>Хм. Не знал. Впрочем, никогда на куче константные объекты не создавал. А почему тут UB?
R>Ну это общее требование стандарта к константным объектам, независимо от области их обитания. Наверное, оставляют разработчикам компиляторов больше возможностей для оптимизаций.
Ясно. Не обращал внимания на этот нюанс. Как-то редко создавал именно константные объекты, обычно константность привнесенная
Здравствуйте, пффф, Вы писали:
П>Ясно. Не обращал внимания на этот нюанс. Как-то редко создавал именно константные объекты, обычно константность привнесенная
Ну да, я тоже не припоминаю в своей практике, чтоб этим кто-то активно пользовался. Это я упомянул к слову, раз уж затронули эту тему.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>Имеем constexpr в конструкторе и const при создании — но выделяются разные участки памяти. Зачем? Сложно проверить и для всех таких constexpr/constexpr не выделять память по 100 раз? S>Вроде бы мелочь, а открываются колоссальные возможности по оптимизации
Пока во время исполнения нет понятия "абсолютно константные данные", и как следствие, — неразличимые между собой копии, — колоссальные возможности по оптимизации не открываются.
(Во время компиляции они есть, но тоже с оговорками. И вот этот дуализм constexpr, конечно, вносит сумятицу).
А давай не будем далеко ходить.
Вот смотри. Пусть у тебя воистину константа
class Konst {};
const Konst* k1 = new const Konst();
const Konst* k2 = new const Konst();
assert(*k1 == *k2); // эквивалентность значений - это мы и так уже ожидаем
assert(k1 == k2); // идентичность объектов - то, что хочешь внедрить ты
// а теперь страшное!delete k1;
delete k2; // ведь мы сделали два new, - значит, и два delete должны
Да и сам по себе constexpr-конструктор не даёт полной гарантии на неизменность.
struct Var {
int x;
constexpr Var(int a, int b) : x(a+b) {}
};
Var v(1, 2);
v.x += 4;
constexpr-ом мы просто обещаем, что эти функции можно вызывать во время компиляции тоже.
Внезапно, переприсваивать во время компиляции тоже можно.
constexpr Var foo(int a, int b, int c) {
Var v(a, b);
v.x += c;
return v;
}
int bar[foo(1, 2, 4).x]; // тут хочешь не хочешь, а константа времени компиляцииtemplate<Var v> struct Buz {};
Buz<foo(1, 2, 4)> buz; // Buz<Var{.x=7}> // константа времени компиляции
Но и во время компиляции важнейшее свойство объектов — уникальность адресов — никуда не девается.
constexpr Var foo1(int a, int b) {
Var* p = new Var(a, 0); // p->x = a
Var* q = new Var(b, 0); // q->x = b
p->x += q->x; // p->x = a+b q не трогаем, это отдельный объект
q->x += p->x; // q->x = a+b+b
Var v = *q;
delete p; delete q;
return v;
}
Здравствуйте, Shmj, Вы писали:
S>constexpr к конструктору — а как мне еще обозначить что не нужно 100 раз выделять память и хватит одного экземпляра на всю программу для всех. const — конструкторов нет. Поля сделал const. Что еще нужно?
Заведи глобальную именованную константу и обращайся к ней изо всех мест. Делов-то.
struct Konst { int x; int y; int z; }; // у таких структур, кстати, конструкторы из коробки constexpr
// глобальные константыconst Konst abc1{1, 2, 3};
const Konst abc2{1, 2, 3}; // знаю-знаю, тебе вот этого как раз не хочетсяconst Konst def {4, 5, 6};
static_assert(&abc1 != &abc2);
// где-то по месту используешь имена вместо выражений
// ..... abc1 ..... abc1 ..... def ..... def .....
// ну ок, допустим, тебе лень где-то держать эти константы, экспортировать их ещё... но хочется синглетонности.
// внимание, трюк!template<Konst k> struct Storage {
static constexpr Konst instance = k;
};
// используешь выражения сколько угодно разconst Konst& xxx = Storage<Konst{1,2,3}>::instance;
const Konst& yyy = Storage<Konst{1,2,3}>::instance;
static_assert(&xxx == &yyy);
Здравствуйте, Кодт, Вы писали:
К>Заведи глобальную именованную константу и обращайся к ней изо всех мест. Делов-то.
Это не удобно — приходится вручную помнить где какие константы использовались.
Принято что для описания UI — C++ не подходит, лучше XML или что-то такое. А почему? Вот вам пример как чисто получается описать UI на языке программирования с возможностью любых сложных действий, когда требуется. При этом выглядит как декларативное описание и по сути таковым является:
return Scaffold(
appBar: AppBar(
leading: const IconButton(
icon: Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: const Text('Example title'),
actions: const [
IconButton(
icon: Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
// body is the majority of the screen.
body: const Center(
child: Text('Hello, world!'),
),
floatingActionButton: const FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
onPressed: null,
child: Icon(Icons.add),
),
);
Здравствуйте, Кодт, Вы писали:
К>Вот смотри. Пусть у тебя воистину константа К>
К>class Konst {};
К>const Konst* k1 = new const Konst();
К>const Konst* k2 = new const Konst();
К>assert(*k1 == *k2); // эквивалентность значений - это мы и так уже ожидаем
К>assert(k1 == k2); // идентичность объектов - то, что хочешь внедрить ты
К>// а теперь страшное!
К>delete k1;
К>delete k2; // ведь мы сделали два new, - значит, и два delete должны
К>
Когда const char* = "text" — все понимают что удалять нельзя — это норм, потому что все понимают что это настоящая константа.
Но уже понятно что в C++ настоящих констант нет. Возможно и добавят что-то типа immutable лет через 10.
Здравствуйте, Shmj, Вы писали:
S>Когда const char* = "text" — все понимают что удалять нельзя — это норм, потому что все понимают что это настоящая константа.
Это в C# — написал "new" и гуляй, можешь ни о чём больше не заботиться. Язык со встроенными памперсами подберёт за тобой всю срань. Когда-нибудь. А в C++ каждому "new" должен соответствовать свой "delete". И это не вопрос константности.
Все твои посты сводятся к следующему: "не хочу учить С++, хочу писать на нём, как на приятных языках". Только невольно возникает вопрос: чего тебе не сидится на твоих "приятных" языках.
--
Справедливость выше закона. А человечность выше справедливости.