Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 27.04.23 10:53
Оценка:
Из p0593, который был принят в C++20:

void process(Stream *stream) {
  unique_ptr<char[]> buffer = stream->read();
  if (buffer[0] == FOO)
    process_foo(reinterpret_cast<Foo*>(buffer.get())); // #1
  else
    process_bar(reinterpret_cast<Bar*>(buffer.get())); // #2
}


(Естественно, принимается что вопрос alignment Foo и Bar решён (или они оба packed)).

Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.
Re: Когда это наконец станет defined behavior?
От: Zhendos  
Дата: 27.04.23 10:59
Оценка: 14 (2)
Здравствуйте, Ip Man, Вы писали:

IM>Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.



Вроде для этого предложили новую функцию std::start_lifetime_as ,
но не знаю принята она в стандарт или нет.
Re[2]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 27.04.23 11:04
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Вроде для этого предложили новую функцию std::start_lifetime_as ,

Z>но не знаю принята она в стандарт или нет.

Нашёл её в C++23 draft.
Re[2]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 27.04.23 12:47
Оценка:
Здравствуйте, Zhendos, Вы писали:

IM>>Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.


Z>Вроде для этого предложили новую функцию std::start_lifetime_as ,


Надо больше обрядов. Что это за религия если мало странных обрядов

ps: пара уже добавлять std::bless<function_name>
Отредактировано 27.04.2023 13:02 kov_serg . Предыдущая версия .
Re: Когда это наконец станет defined behavior?
От: reversecode google
Дата: 27.04.23 12:58
Оценка: :)
это бред
у гугла до черта кода которые делаю такие касты
их uint8_t* в какой то объект(структуру)

и если это УБ
то прощай весь софт, так же ?

есть где то на ютубе презентация автора этого лафт-тайм-аз
и по моему там чуть чуть другой пример, как мне кажется(могу ошибаться)
Re[2]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 27.04.23 13:42
Оценка:
Здравствуйте, reversecode, Вы писали:

R>это бред

R>у гугла до черта кода которые делаю такие касты
R>их uint8_t* в какой то объект(структуру)

R>и если это УБ

R>то прощай весь софт, так же ?

Все так делают. Но формально это UB.
Re[3]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 14:01
Оценка:
Здравствуйте, Ip Man, Вы писали:

IM>Все так делают. Но формально это UB.


В тему приглашается 45й который на скиле по хардкору пояснит что нет никаких проблем писать код, не содержащий уб, и что его достало нытьё неосиляторов и что нет ничего сложного пофиксить старый проект и пересобрать более новым компилятором.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: Когда это наконец станет defined behavior?
От: reversecode google
Дата: 27.04.23 14:13
Оценка: 1 (1)
хм
нашел видео
у думлера тотже пример
https://youtu.be/_qzMpk-22cc?t=2606

еще до кучи
https://habr.com/ru/articles/680008/

в коментах lifetime там ребята чуть чуть обсуждали когда все таки не так уж и страшно

https://youtu.be/pbkQG09grFw?t=1467
Re[4]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 27.04.23 16:35
Оценка:
Здравствуйте, T4r4sB, Вы писали:

IM>>Все так делают. Но формально это UB.

TB>В тему приглашается 45й который на скиле по хардкору пояснит что нет никаких проблем писать код, не содержащий уб, и что его достало нытьё неосиляторов и что нет ничего сложного пофиксить старый проект и пересобрать более новым компилятором.

Пока ждем 45-ого могу сказать: такой исходный код
Автор: Ip Man
Дата: 27.04.23
code review обычно не пройдёт: big-endian/little-endian, проверка размера прочитанных данных, проверка диапазонов значений — где всё это? А без таких проверок reinterpret_cast смысла не имеет.
И каждый день — без права на ошибку...
Re[4]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 17:21
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://habr.com/ru/articles/680008/


Офигеть

Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.

То есть этот код содержит УБ?
int g=0;

int bar() {
  ++g;
  return g;
}

int foo(const int& a) {
  return a + bar() + a;
}

int main() {
  printf("%i\n", foo(g));
}
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 27.04.2023 17:22 T4r4sB . Предыдущая версия .
Re[5]: Когда это наконец станет defined behavior?
От: reversecode google
Дата: 27.04.23 17:34
Оценка:
какой ответа от меня ожидают ?

вон гугл reinterpet_cast пользуется и даже ЕМ пользуются всякими уб и деньгу зашибают оба

а про уб же написано — нужно что бы пугать детей

или к примеру из народного

И незаряженное ружье один раз в году само стреляет

тоже ведь УБ, только народное
Re[5]: Когда это наконец станет defined behavior?
От: σ  
Дата: 27.04.23 17:51
Оценка: +1
TB>

Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior

TB>То есть этот код содержит УБ?

А где в нём происходи что-нибудь из цитируемого?
Re: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 17:56
Оценка:
Здравствуйте, Ip Man, Вы писали:

IM>(Естественно, принимается что вопрос alignment Foo и Bar решён (или они оба packed)).

А почему placement new тут не используется с параметром выравнивания?
Sic luceat lux!
Re: Когда это наконец станет defined behavior?
От: σ  
Дата: 27.04.23 18:06
Оценка: -2
Тебе зачем?
Re[6]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 18:13
Оценка:
Здравствуйте, σ, Вы писали:

σ>А где в нём происходи что-нибудь из цитируемого?


Модификация константного объекта через неконстантный доступ.
Или "константный объект" это только то, что изначально объявлено с модификатором const, а не результат разыменования const&?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[2]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 27.04.23 18:24
Оценка:
Здравствуйте, Kernan, Вы писали:

K>А почему placement new тут не используется с параметром выравнивания?


Стандарт не гарантирует. Объект-то будет создан и даже default initialized, но нигде не сказано, что там останутся те же байты.
Re[7]: Когда это наконец станет defined behavior?
От: watchmaker  
Дата: 27.04.23 18:35
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Или "константный объект" это только то, что изначально объявлено с модификатором const, а не результат разыменования const&?


Только объект, что изнчально был const.

На одной пратформе компилятор может расположить его в обычной оперативной памяти, на другой — помеместить в области памяти с защитой от записи, на третьей — вообще оставить в ROM. Универсального ответа что произойдёт при попытке изменить такой объект нет — поэтому декларируется неопределённое поведение.
Re[3]: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 18:43
Оценка:
Здравствуйте, Ip Man, Вы писали:

IM>Здравствуйте, Kernan, Вы писали:


K>>А почему placement new тут не используется с параметром выравнивания?


IM>Стандарт не гарантирует. Объект-то будет создан и даже default initialized, но нигде не сказано, что там останутся те же байты.

Погоди. Это как? placement new же не меняет память, а работает поверх того что есть. Кроме того, вроде с POD точно должно быть нормально. Разве нет?
Sic luceat lux!
Re[4]: Когда это наконец станет defined behavior?
От: σ  
Дата: 27.04.23 18:54
Оценка: +1
IM>>Стандарт не гарантирует. Объект-то будет создан и даже default initialized, но нигде не сказано, что там останутся те же байты.
K>Погоди. Это как? placement new же не меняет память, а работает поверх того что есть.
https://timsong-cpp.github.io/cppwp/n4868/basic.indet#1
Re[5]: Когда это наконец станет defined behavior?
От: _NN_  
Дата: 27.04.23 18:58
Оценка: -1
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, reversecode, Вы писали:


R>>https://habr.com/ru/articles/680008/


TB>Офигеть

TB>

TB>Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.

TB>То есть этот код содержит УБ?
TB>
TB>int g=0;

TB>int bar() {
TB>  ++g;
TB>  return g;
TB>}

TB>int foo(const int& a) {
TB>  return a + bar() + a;
TB>}

TB>int main() {
TB>  printf("%i\n", foo(g));
TB>}
TB>


Насколько я понимаю неопределённое поведение у нас только из-за разного порядка вычисления подвыражений в "a + bar() + a".

Если переписать как:
auto x = a + a;
auto y = bar();
return x + y;


То у нас будет всё определенно.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 27.04.23 19:07
Оценка: +1
Здравствуйте, Kernan, Вы писали:

K>Погоди. Это как? placement new же не меняет память, а работает поверх того что есть. Кроме того, вроде с POD точно должно быть нормально. Разве нет?


placement new инициализирует объект, в данном случае он будет default-initialized (т.к. определенного юзером конструктора очевидно нет).

Никто не гарантирует, что дефолтная инициализация сохранит то, что было в памяти до этого.
Re[6]: Когда это наконец станет defined behavior?
От: σ  
Дата: 27.04.23 19:10
Оценка:
_NN>Насколько я понимаю неопределённое поведение у нас только из-за разного порядка вычисления подвыражений в "a + bar() + a".
Ты про https://timsong-cpp.github.io/cppwp/n4868/intro.execution#10.sentence-4
> If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined
?

side effects — все в функции, а, как известно
> For each function invocation F, for every evaluation A that occurs within F and every evaluation B that does not occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is sequenced before B or B is sequenced before A.
Re[6]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 19:11
Оценка: -1
Здравствуйте, _NN_, Вы писали:

> у нас только из-за разного порядка вычисления подвыражений в "a + bar() + a".


Оператор + левоассоциативный, второе сложение в любом случае выполнится после первого.

_NN>Если переписать как:

_NN>
_NN>auto x = a + a;
_NN>auto y = bar();
_NN>return x + y;
_NN>


Поздравляю, ты поменял результат.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[5]: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 20:01
Оценка: +1
Здравствуйте, Ip Man, Вы писали:

IM>placement new инициализирует объект, в данном случае он будет default-initialized (т.к. определенного юзером конструктора очевидно нет).

IM>Никто не гарантирует, что дефолтная инициализация сохранит то, что было в памяти до этого.
Понял, надо было просто подумать получше. Если в классе A есть поле int a{0}, то при placment new этот int в 0 и уйдёт даже если конструктор дефолтный. Ну и прочее.
Почему бы просто не довести placement new до ума чтобы он не делал инициализацию? Добавить new (addr) T noctor; Придумали какие-то дикие костыли с reinterpret_cast когда всё уже было.
Sic luceat lux!
Отредактировано 27.04.2023 20:02 Kernan . Предыдущая версия .
Re[6]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 20:04
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Почему бы просто не довести placement new до ума чтобы он не делал инициализацию?


Ээээ, а разве он не для того придумал, чтоб вызывать конструктор на конкретной области памяти?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[7]: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 20:11
Оценка: -2
Здравствуйте, T4r4sB, Вы писали:

TB>Ээээ, а разве он не для того придумал, чтоб вызывать конструктор на конкретной области памяти?

Он придуман для того, чтобы создать объект на конкретной области памяти, а уж вызовет ли он конструктор или нет зависит от желания программиста. Можно, конечно, возразить задав вопрос о том, что делать с деструктором, но всё это вторично и можно тупо заставить писать тривиальные деструкторы чтобы использовать новую фишку. Короче, С++ программист понимает что хочет получить, а не как в Rust "мы ограничиваем вас borrow checker-ом потому, что вы тупой дегенерат".
Sic luceat lux!
Отредактировано 27.04.2023 20:18 Kernan . Предыдущая версия .
Re[8]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 20:17
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Он придуман для того, чтобы создать объект на конкретной области памяти,


А разве это не синоним "вызвать конструктор"?
Просто если не вызывать конструктор, то что он должен делать-то тогда? nop?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 20:19
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>А разве это не синоним "вызвать конструктор"?

TB>Просто если не вызывать конструктор, то что он должен делать-то тогда? nop?
Ты мне за семантику предъявляешь что ли?
Sic luceat lux!
Re[10]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 20:22
Оценка:
Здравствуйте, Kernan, Вы писали:

TB>>А разве это не синоним "вызвать конструктор"?

TB>>Просто если не вызывать конструктор, то что он должен делать-то тогда? nop?
K>Ты мне за семантику предъявляешь что ли?

Не, для себя интересуюсь XD
Как по-твоему должен выглядеть оператор placement new не вызывающий конструктор, и какой в нём физический смысл?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: Когда это наконец станет defined behavior?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 20:28
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Как по-твоему должен выглядеть оператор placement new не вызывающий конструктор, и какой в нём физический смысл?

Так я выше сказал, размещение объекта на подготовленном куске памяти. При этом, он может и границы проверить, и типы отдать, и алайнмент правильный поюзать чтобы там не было мерзких паддингов, и даже endiannes порешать если надо. Всё это стандартным способом создания объекта. Мы просто полагаем что область памяти валидна, правильно инициализирована и т.п., а значит конструктор вызывать не надо.
Sic luceat lux!
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 20:36
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Так я выше сказал, размещение объекта на подготовленном куске памяти. При этом, он может и границы проверить, и типы отдать, и алайнмент правильный поюзать чтобы там не было мерзких паддингов, и даже endiannes порешать если надо.


Ээээ, что-то по описанию больше похоже на десериализацию, чем на placement new, то есть абсолютно другая задача.

K>Всё это стандартным способом создания объекта. Мы просто полагаем что область памяти валидна, правильно инициализирована и т.п., а значит конструктор вызывать не надо.


Дык если в этой области памяти уже лежат правильные данные, то что такой placement new в принципе может полезного сделать?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[5]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 27.04.23 20:41
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Пока ждем 45-ого могу сказать: такой исходный код
Автор: Ip Man
Дата: 27.04.23
code review обычно не пройдёт: big-endian/little-endian


При передаче данных на одной машине через shared memory или пайпы это не требуется.
Отредактировано 28.04.2023 4:45 so5team . Предыдущая версия .
Re[9]: Когда это наконец станет defined behavior?
От: wander  
Дата: 27.04.23 21:38
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>А разве это не синоним "вызвать конструктор"?


Нет конечно. Конструктор выполняет иницализацию, но не любая инициализация происходит с вызовом конструктора (помним про тривиальные типы, или, например, про агрегаты).
Иными словами, конструктор — это частный случай инициализации, а не общий.
Re[10]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 21:42
Оценка:
Здравствуйте, wander, Вы писали:

W>Нет конечно. Конструктор выполняет иницализацию, но не любая инициализация происходит с вызовом конструктора (помним про тривиальные типы, или, например, про агрегаты).


Ок, в языке не хватает placement aggregate initialization. А какой ещё случай имеет смысл?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: Когда это наконец станет defined behavior?
От: wander  
Дата: 27.04.23 21:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Ок, в языке не хватает placement aggregate initialization. А какой ещё случай имеет смысл?


В смысле не хватает?
    char buf[100];
    
    int* p = new(buf) int[20] {1,2,3,4};
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 27.04.23 21:49
Оценка:
Здравствуйте, wander, Вы писали:

W>В смысле не хватает?


А, точно. Тогда я не понимаю, о чём говорилось в сообщении от Kernan 27.04.23 23:01
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 28.04.23 09:45
Оценка:
Здравствуйте, so5team, Вы писали:

BFE>>Пока ждем 45-ого могу сказать: такой исходный код
Автор: Ip Man
Дата: 27.04.23
code review обычно не пройдёт: big-endian/little-endian

S>При передаче данных на одной машине через shared memory или пайпы это не требуется.
Вряд ли для таких случаев используют Stream.

ЗЫ Я не говорю, что это совсем не нужно, может иногда понадобится для оптимизации.
И каждый день — без права на ошибку...
Re[7]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 28.04.23 10:01
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Пока ждем 45-ого могу сказать: такой исходный код
Автор: Ip Man
Дата: 27.04.23
code review обычно не пройдёт: big-endian/little-endian

S>>При передаче данных на одной машине через shared memory или пайпы это не требуется.
BFE>Вряд ли для таких случаев используют Stream.

По разному бывает.

BFE>ЗЫ Я не говорю, что это совсем не нужно, может иногда понадобится для оптимизации.


Не только. Например, некая программулина собирает и обрабатывает некоторые данные с использованием библиотек X и Y. Библиотеки большие, сложные, и не всегда работают надежно, т.е. могут падать время от времени и крашить приложение, в котором используются. Для преодоления этой проблемы приложение разбивается на процессы: N процессов посредством X и Y собирают и обрабатывают данные, результаты обработки доставляются в головной процесс через пайпы и shared memory. Если какой-то из этих N процессов падает, то его рестартуют. Тут ни про endianness не приходится задумываться, ни (по большому счету) про верификацию передаваемых между процессами данных.

Другой пример: программе нужно работать со специализированным внешним устройством через библиотеку, которая предоставлена поставщиком устройства, и которая позволяет работать с устройством только синхронно. Но это устройство имеет свойство время от времени засыпать, разбудить его можно посредством повторного вызова функции init из этой библиотеки. Однако, если устройство "уснуло" на синхронном вызове, то этот вызов не вернет назад управление даже если кто-то параллельно вызовет init. Библиотека закрытая, влезть и поправить ее нельзя. Тогда работа с устройством выносится в отдельный процесс, общение с которым идет через пайпы. Если отдельный процесс завис из-за того, что устройство в очередной раз "уснуло", то он просто убивается, и запускается новый, который вызывает init и затем успешно работает пока устройство снова уснет.
Re[7]: Когда это наконец станет defined behavior?
От: σ  
Дата: 28.04.23 10:48
Оценка:
_NN_>> у нас только из-за разного порядка вычисления подвыражений в "a + bar() + a".

TB> Оператор + левоассоциативный


При чём тут это?

TB> второе сложение в любом случае выполнится после первого.


А чтения из a — в любом порядке. Оба до вызова bar, оба после, или с вызовом между.
Re[8]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 28.04.23 11:11
Оценка:
Здравствуйте, σ, Вы писали:

TB>> Оператор + левоассоциативный


σ>При чём тут это?


При том что второе сложение обязано выполниться после первого

TB>> второе сложение в любом случае выполнится после первого.


σ>А чтения из a — в любом порядке. Оба до вызова bar, оба после, или с вызовом между.


И что же гцц даже с о3 зассал один раз прочитать а и удвоить в регистре?
Ты не видишь что от порядка чтений меняется результат?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: Когда это наконец станет defined behavior?
От: σ  
Дата: 28.04.23 14:42
Оценка:
TB>>> Оператор + левоассоциативный

σ>>При чём тут это?


TB>При том что второе сложение обязано выполниться после первого


Что в стандарте это подтверждает?

TB>>> второе сложение в любом случае выполнится после первого.


σ>>А чтения из a — в любом порядке. Оба до вызова bar, оба после, или с вызовом между.


TB>И что же гцц даже с о3 зассал один раз прочитать а и удвоить в регистре?


ХЗ. Missing optimization? MSVC вроде не ссыт https://godbolt.org/z/v8TzGK13K

TB>Ты не видишь что от порядка чтений меняется результат?


И?
Re[10]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 28.04.23 15:04
Оценка:
Здравствуйте, σ, Вы писали:

σ>Что в стандарте это подтверждает?


Выражение в теле функции однозначно парсится как

Operator+(operator+(a, bar()), a)

σ>ХЗ. Missing optimization? MSVC вроде не ссыт https://godbolt.org/z/v8TzGK13K


Ок, плохой пример, bar()+a неоднозначно.

int foo(const int& a) {
  int ll = a;
  int l = ll + bar();
  return l + a;
}



TB>>Ты не видишь что от порядка чтений меняется результат?


σ>И?


Ну уб получается.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 28.04.2023 15:10 T4r4sB . Предыдущая версия .
Re[11]: Когда это наконец станет defined behavior?
От: σ  
Дата: 28.04.23 15:18
Оценка:
σ>>Что в стандарте это подтверждает?

TB>Выражение в теле функции однозначно парсится как


TB>Operator+(a,operator+(bar(), a))


Допустим. Это как-то противоречит
> чтения из a — в любом порядке. Оба до вызова bar, оба после, или с вызовом между.
?

σ>>ХЗ. Missing optimization? MSVC вроде не ссыт https://godbolt.org/z/v8TzGK13K


TB>Ок, плохой пример, bar()+a неоднозначно.


TB>
TB>int foo(const int& a) {
TB>  int ll = a;
TB>  int l = ll + bar();
TB>  return l + a;
TB>}
TB>


TB>Хотя ret 0 это жесть


А сколько должно быть

TB>>>Ты не видишь что от порядка чтений меняется результат?


σ>>И?


TB>Ну уб получается.


Почему?
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 28.04.23 15:30
Оценка:
Здравствуйте, σ, Вы писали:

Да, согласен, может сначала прочитать второй аргумент а потом вычислить первый.
Поэтому я исправил пример:


TB>>
TB>>int foo(const int& a) {
TB>>  int ll = a;
TB>>  int l = ll + bar();
TB>>  return l + a;
TB>>}
TB>>


Гцц по прежнему два чтения из памяти.

TB>>Хотя ret 0 это жесть


σ>А сколько должно быть :???


С этой инструкцией, я просто не сразу вспомнил что означает число в команде ret.



σ>Почему?


Потому что от желания оптимизатора может поменяться результат функции
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[13]: Когда это наконец станет defined behavior?
От: σ  
Дата: 28.04.23 15:47
Оценка:
TB>Гцц по прежнему два чтения из памяти.

¯\_(ツ)_/¯ Может, посчитали, что прочитать 2 раза подряд — недорого

σ>>Почему?


TB>Потому что от желания оптимизатора может поменяться результат функции


Как-то мало для UB
Re[14]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 28.04.23 15:48
Оценка:
Здравствуйте, σ, Вы писали:

TB>>Потому что от желания оптимизатора может поменяться результат функции


σ>Как-то мало для UB


Лол это и называется уб

σ>¯\_(ツ)_/¯ Может, посчитали, что прочитать 2 раза подряд — недорого


А почему в таком коде решили, что прочитать 2 раза подряд — дорого?
int foo(int* a, float* b) {
  *a = 8;
  *b = 42.0;
  return *a + 9;
}

https://godbolt.org/z/xq7nPEMz7
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 28.04.2023 17:11 T4r4sB . Предыдущая версия .
Re[15]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 28.04.23 20:04
Оценка:
Здравствуйте, T4r4sB, Вы писали:


TB>>>Потому что от желания оптимизатора может поменяться результат функции


σ>>Как-то мало для UB


TB>Лол это и называется уб


Я думаю, тебе не помешало бы разобраться с такими понятиями как undefined behavior, unspecified behavior и implementation defined behavior. По иронии судьбы первые два пункта в этом списке имеют одинаковую аббревиатуру (UB), но при этом очень разный смысл. Можно почитать здесь: https://en.cppreference.com/w/cpp/language/ub.

Вдобавок в параграфе с описанием unspecified behavior есть еще очень полезная ссылка — Order of evaluation, имеющая непосредственное отношение к обсуждаемому вопросу:

There is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression a() + b() + c() is parsed as (a() + b()) + c() due to left-to-right associativity of operator+, but c() may be evaluated first, last, or between a() or b() at run time


То есть, порядок выполнения операций (ассоциативность) и порядок вычисления операндов (подвыражений) — это две разные и независимые вещи. Порядок вычисления операндов регулируется отношениями "sequenced before/after", но он определен далеко не для всех случаев. Во многих случаях этот порядок отдан на откуп разработчикам компиляторов и относится к UNSPECIFIED behavior. И это совсем не то же самое, что UNDEFINED behavior. И аббревиатура UB, сколько мне попадалось, всегда употребляется только в смысле undefined behavior.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 28.04.2023 20:29 rg45 . Предыдущая версия . Еще …
Отредактировано 28.04.2023 20:28 rg45 . Предыдущая версия .
Отредактировано 28.04.2023 20:23 rg45 . Предыдущая версия .
Отредактировано 28.04.2023 20:22 rg45 . Предыдущая версия .
Отредактировано 28.04.2023 20:20 rg45 . Предыдущая версия .
Отредактировано 28.04.2023 20:16 rg45 . Предыдущая версия .
Отредактировано 28.04.2023 20:09 rg45 . Предыдущая версия .
Re[16]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 28.04.23 20:29
Оценка: -1
Здравствуйте, rg45, Вы писали:

TB>>Лол это и называется уб


R>Я думаю, тебе не помешало бы разобраться с такими понятиями как undefined behavior, unspecified behavior и implementation defined behavior.


То, от чего меняется логика при оптимизации — это как раз undefined behavior.
Что и написано по твоей ссылке, целый раздел есть "UB and optimization".

R>То есть, порядок выполнения операций (ассоциативность) и порядок вычисления операндов (подвыражений) — это две разные и независимые вещи.


Да, мой изначальный пример был плох, потому что зависел от порядка вычисления операндов.
Я уже исправил.
int bar();

int foo(const int& a) {
  int ll = a;
  int l = ll + bar();
  return l + a;
}

Так вот, почему гцц ссыт убрать лишнее чтение из памяти?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 28.04.2023 20:32 T4r4sB . Предыдущая версия .
Re[17]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 28.04.23 20:48
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>То, от чего меняется логика при оптимизации — это как раз undefined behavior.

TB>Что и написано по твоей ссылке, целый раздел есть "UB and optimization".

Я не очень понимаю, для чего тебе понадобилось пeрефразировать собственные высказывания, но перед этим ты утверждал буквально следующее:

TB>Потому что от желания оптимизатора может поменяться результат функции
TB>Лол это и называется уб


Так вот это не верно. Может поменяться результат вызова функции и это не обязательно будет UB (undefined behavior).

Пример:

int a = 42;
int b = foo(a, a += 1);

Результат может быть разным. Но это проявление unspecified behavior, а не undefined.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 28.04.2023 21:42 rg45 . Предыдущая версия . Еще …
Отредактировано 28.04.2023 20:51 rg45 . Предыдущая версия .
Re[17]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 08:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

R>>Я думаю, тебе не помешало бы разобраться с такими понятиями как undefined behavior, unspecified behavior и implementation defined behavior.


TB>То, от чего меняется логика при оптимизации — это как раз undefined behavior.


Таки нет. Undefined — это когда от твоего нарушения может взорваться вообще всё и не только в этом месте. Unspecified — это когда что-то произойдёт на выбор из описанных вариантов, но что именно — на этапе написания зафиксировать нельзя; причём в стандарте все такие случаи имеют локальный эффект (например, порядок вычисления аргументов функции или операндов в a+b — это не повлияет уже на соседний оператор).
И вот такие вещи, как порядок вычисления аргументов функции, от оптимизаций могут меняться весьма значительно.

R>>То есть, порядок выполнения операций (ассоциативность) и порядок вычисления операндов (подвыражений) — это две разные и независимые вещи.


TB>Так вот, почему гцц ссыт убрать лишнее чтение из памяти?


Тут и банально, и нет.

С одной стороны, он не знает, что делает этот bar(), может ли он поменять ту переменную, которая тебе передана по ссылке как a.
Запиши вместо декларации bar(), например: int bar() { return 1; } и увидишь, что он соптимизировал оба чтения в одно: (gcc 9.4.0, -O2, убрал незначащее)

Z3fooRKi:
        movl    (%rdi), %eax
        leal    1(%rax,%rax), %eax
        ret

Видно, что bar() заинлайнилась, а чтение переменной "a" одно на оба случая.

А вот теперь фокус — подставляем барьер памяти в bar():

int bar() {                                                                    
  std::atomic_signal_fence(std::memory_order_acquire);                         
  return 1;                                                                    
}


И код получился вообще потрясающий:

_Z3fooRKi:
        movl    (%rdi), %edx
        movl    (%rdi), %eax
        leal    1(%rdx,%rax), %eax
        ret


Одну и ту же "a" читаем дважды, bar() как бы выполнилось между ними, хотя её результат подставлен после.

Вывод — срабатывал принцип "мы не знаем, что делает bar(), значит, он мог поменять память как угодно".

А вот что меня таки смущает — почему это происходит при том, что в аргументе было "const int& a", а не "int& a". Clang — точно так же. Это значит, что константность для них действует одинаково как "мы не имеем права это менять", но не действует как "это не может поменять кто-то снаружи", несмотря на то, что формально это const.

Вот это, скорее всего, очевидно, если правильно и дословно вкурить стандарт, но я сейчас не осилил вкурить его нужным образом. Тут если кто-то ещё прокомментирует, с разбором конкретных пунктов, будет полезно.

И, естественно, всё это ещё в контексте предположений о том, что компилятор не может переставить порядок выполнения сложений в этой последовательности. Вот этот момент меня тоже смущает, но, может, его тут уже разрешили (надо перечитать, но рассказ про левоассоциативность сложения может решать этот аспект).
The God is real, unless declared integer.
Отредактировано 29.04.2023 8:51 netch80 . Предыдущая версия .
Re[3]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 08:57
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

IM>>>Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.


Z>>Вроде для этого предложили новую функцию std::start_lifetime_as ,


_>Надо больше обрядов. Что это за религия если мало странных обрядов


Ну почему обряд... в этом есть своя логика, если думать о том, как реализуется контроль алиасинга (на всех уровнях).
Обрядом здесь скорее является желание активизировать его в любом случае, а кто не спрятался — сам виноват. Я по умолчанию бы предпочёл видеть все операции с памятью как неявные барьеры, а кому от этого медленно — вот там уже помечать нужные куски кода всеми подобными средствами.

_>ps: пара уже добавлять std::bless<function_name>


Это в другой язык, всё уже есть.
The God is real, unless declared integer.
Re[18]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 09:45
Оценка:
Здравствуйте, netch80, Вы писали:

N>Таки нет. Undefined — это когда от твоего нарушения может взорваться вообще всё и не только в этом месте.


Я говорю о том, как оно работает на этапе компиляции в реальности.

N>А вот что меня таки смущает — почему это происходит при том, что в аргументе было "const int& a", а не "int& a".


Ага, и я о том же.
Вот тут я даже не знаю, чагойта стандартизаторы испугалися
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[18]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 29.04.23 10:04
Оценка: +1
Здравствуйте, netch80, Вы писали:

TB>
TB>int bar();

TB>int foo(const int& a) {
TB>  int ll = a;
TB>  int l = ll + bar();
TB>  return l + a;
TB>}
TB>


N>А вот что меня таки смущает — почему это происходит при том, что в аргументе было "const int& a", а не "int& a". Clang — точно так же. Это значит, что константность для них действует одинаково как "мы не имеем права это менять", но не действует как "это не может поменять кто-то снаружи", несмотря на то, что формально это const.


Так ясно почему — константность ссылки не гарантирует константности объекта. Один и тот же объект можно привязать одновременно к множеству разных ссылок, как константных, так и неконстантных. А функция bar может может иметь непостредственный доступ к объекту, помимо той ссылки, которая передается в функцию foo:

http://coliru.stacked-crooked.com/a/5197fe8b39464268

////////////////////////////////////////////////////////
// main.cpp

#include <iostream>

int bar();

int foo(const int& a) {
  int ll = a;
  int l = ll + bar();
  return l + a;
}

int main()
{
   extern int x;

   std::cout << x << std::endl;        // -> 42
   std::cout << foo(x) << std::endl;   // -> 128
   std::cout << x << std::endl;        // -> 43
}

////////////////////////////////////////////////////////
// bar.cpp

int x = 42;

int bar() {
   return ++x;
}
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 29.04.2023 10:16 rg45 . Предыдущая версия . Еще …
Отредактировано 29.04.2023 10:13 rg45 . Предыдущая версия .
Re[19]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 10:27
Оценка:
Здравствуйте, rg45, Вы писали:

R>А функция bar может может иметь непостредственный доступ к объекту, помимо той ссылки, которая передается в функцию foo:


Надо стандартизаторам идею подкинуть: а почему б такую ситуацию тоже не назвать UB? Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется! Это ж сколько можно долей процента выиграть в реальных приложениях! А сколько будет новых непонятных падений!
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[4]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 10:32
Оценка:
Здравствуйте, netch80, Вы писали:

N> Я по умолчанию бы предпочёл видеть все операции с памятью как неявные барьеры


То есть в цикле
while (*dst++ = *src++);

Значит каждый раз не только читать содержимое указателей src,dst, но и каждый раз читать содержимое куска памяти, где лежат значения этих указателей?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[20]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 29.04.23 10:34
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Надо стандартизаторам идею подкинуть: а почему б такую ситуацию тоже не назвать UB? Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется! Это ж сколько можно долей процента выиграть в реальных приложениях! А сколько будет новых непонятных падений!


Другими словами, ты предлагаешь запретить привязывать константные ссылки к неконстантным объектам? Сомнительная идея как по мне. Передали константную ссылку — значит, тот участок логики, которому передали ссылку, может только читать данные, но не имеет права менять их. Например, это процедура вывода данных на экран или в файл — ее дело только вывод данных. Но это ж не значит, что эти данные не может менять вообще нигде и никто. Таким образом ссылки выступают как средство разграничения прав доступа — кто-то может и читать, и писать, а кто-то только читать. И это очень даже полезная возможность.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 29.04.2023 10:59 rg45 . Предыдущая версия . Еще …
Отредактировано 29.04.2023 10:42 rg45 . Предыдущая версия .
Отредактировано 29.04.2023 10:41 rg45 . Предыдущая версия .
Отредактировано 29.04.2023 10:40 rg45 . Предыдущая версия .
Re[17]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 29.04.23 11:29
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>
TB>int bar();

TB>int foo(const int& a) {
TB>  int ll = a;
TB>  int l = ll + bar();
TB>  return l + a;
TB>}
TB>

TB>Так вот, почему гцц ссыт убрать лишнее чтение из памяти?

Кстати, неплохой вопрос к собеседованиям.
--
Справедливость выше закона. А человечность выше справедливости.
Re[20]: Когда это наконец станет defined behavior?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.04.23 13:15
Оценка: +2
Здравствуйте, T4r4sB, Вы писали:

TB>Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется!


Если объект создается константным — вправе, и вполне себе предполагает (например, если объект статический, и есть возможность разместить его в RO-секции). А если откуда-то просто приходит ссылка на уже существующий объект, то весь смысл const заключается лишь в запрете его изменения через данную ссылку.
Re[5]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 15:42
Оценка:
Здравствуйте, T4r4sB, Вы писали:

N>> Я по умолчанию бы предпочёл видеть все операции с памятью как неявные барьеры


TB>То есть в цикле

TB>
TB>while (*dst++ = *src++);
TB>

TB>Значит каждый раз не только читать содержимое указателей src,dst, но и каждый раз читать содержимое куска памяти, где лежат значения этих указателей?

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

По пунктам:

1. Если src и dst это локальные переменные функции, и никто не берёт их адрес для каких-то целей (или делает это позже данного кода), то то, что я говорю, на них не распространяется. Эти переменные могут быть в стеке, в регистре, прыгать туда-обратно по настроению компилятора — неважно.
Аргументы функции в этом смысле включаются в локальные переменные — если они не приняты по ссылке (а нахрена?)

2. А вот содержимое памяти по этим указателям — да, должен читать. И ровно это, если ты имеешь в виду логику strcpy (ты ведь зачем-то такой пример взял, да?), происходит и сейчас. Компилятор обязан читать и писать память под указателями, причём даже по двум причинам: указатели одинакового типа — значит, логика алиасинга "память под указателями разных типов независима", и указатели типа char* — что убивает независимость операций (есть такое специальное правило).

3. Я что-то не понял отношения между частями твоего вопроса. Если бы это было "не только читать содержимое куска памяти... но и читать содержимое указателей", было бы понятно. А так — нет.

То, что я имел в виду изначально, это вещи следующего вида.
Самое простое: если мы видим, например,

int a, b, c; // глобальные
void foo() {
  b = a;
  c = a;
}


то объединять их не положено, пока не будет разрешено, например, в стиле

[[aliasing(relaxed)]]
void foo() {
  b = a;
  c = a;
}


Или, например, у нас есть код:

void boo(float *a, int n, int *c) {
  for (int i = 0; i < n; ++i) { a[i] *= *c; }
}


Сейчас за счёт разнотипности *a и *c считается, что присвоение любому a[i] не может влиять на значение *c, поэтому при любой оптимизации значение *c начинает кэшироваться.
Берём тот же gcc:

  asm1
boo:
.LFB0:
        testl   %esi, %esi
        jle     .L1
        pxor    %xmm1, %xmm1
        leal    -1(%rsi), %eax
        cvtsi2ssl       (%rdx), %xmm1 <-- Вот тут один раз прочитал и запомнил
        leaq    4(%rdi,%rax,4), %rax
.L3:
        movss   (%rdi), %xmm0
        addq    $4, %rdi
        mulss   %xmm1, %xmm0
        movss   %xmm0, -4(%rdi)
        cmpq    %rax, %rdi
        jne     .L3
.L1:
        ret


А теперь меняем int *c на float *c, и это разрешение компилятору уходит, потому что он уже подозревает, что присвоение a[i] может повлиять на *c:

  asm2
boo:
        testl   %esi, %esi
        jle     .L1
        movq    %rdi, %rax
        leal    -1(%rsi), %ecx
        leaq    4(%rdi,%rcx,4), %rcx
.L3:
        movss   (%rax), %xmm0
        mulss   (%rdx), %xmm0 <-- Читает на каждой итерации
        movss   %xmm0, (%rax)
        addq    $4, %rax
        cmpq    %rcx, %rax
        jne     .L3
.L1:
        ret


А теперь я добавляю слово restrict (увы, только C, не C++) к float *c, и оно возвращается к однократному чтению:

  asm3
boo:
        testl   %esi, %esi
        jle     .L1
        movss   (%rdx), %xmm1 <-- Прочли один раз и запомнили
        movq    %rdi, %rax
        leal    -1(%rsi), %edx
        leaq    4(%rdi,%rdx,4), %rdx
.L3:
        movaps  %xmm1, %xmm0
        mulss   (%rax), %xmm0
        movss   %xmm0, (%rax)
        addq    $4, %rax
        cmpq    %rdx, %rax
        jne     .L3
.L1:
        ret


Вот то что я хочу видеть по умолчанию — это такой себе anti-restrict (как в asm2) для всех операций с памятью (то есть с любым, что не является локальной переменной, у которой не брали адрес), а кроме того запрет переупорядочения доступа к ним.
В примере 2, если кто-то считает при этом, что недостаточно скорости для доступа к *c, то он может сложить в локальную переменную — или таки атрибутами выставить облегчение, ослабив тотальный алиасинг — в пределах одного куска исходного кода.

Надеюсь, теперь идея понятна?
The God is real, unless declared integer.
Отредактировано 29.04.2023 15:56 netch80 . Предыдущая версия .
Re[19]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 15:44
Оценка:
Здравствуйте, T4r4sB, Вы писали:

N>>Таки нет. Undefined — это когда от твоего нарушения может взорваться вообще всё и не только в этом месте.


TB>Я говорю о том, как оно работает на этапе компиляции в реальности.


И я о том же. В чём ты видишь разницу?
The God is real, unless declared integer.
Re[20]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 15:51
Оценка:
Здравствуйте, T4r4sB, Вы писали:

R>>А функция bar может может иметь непостредственный доступ к объекту, помимо той ссылки, которая передается в функцию foo:


TB>Надо стандартизаторам идею подкинуть: а почему б такую ситуацию тоже не назвать UB? Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется! Это ж сколько можно долей процента выиграть в реальных приложениях! А сколько будет новых непонятных падений!


Шутки шутками, а когда я писал позапрошлый комментарий, мне так и казалось. Слишком уж тонкая материя — сейчас смутно вспоминается, что я эту проблему читал, но поскольку сам на грабли не наступал, то оно и забылось.

По-"бытовому" const для объекта как источник предположения, что он не будет меняться, очень полезен. Но вводить его с учётом описанного тут я бы не стал, тут скорее нужно два разных уровня const — один "обещаем что не будет меняться" и второй послабее — запрет изменения через конкретные ссылку/указатель.
Чуть громоздко, но ясность ситуации, думаю, будет важнее.
The God is real, unless declared integer.
Re[21]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 15:59
Оценка:
Здравствуйте, rg45, Вы писали:

R>Другими словами, ты предлагаешь запретить привязывать константные ссылки к неконстантным объектам? Сомнительная идея как по мне.


Я такого у него не читал.
А вот считать, что раз ссылка константная, то и объект не будет изменяться никем со стороны по крайней мере время жизни этой конкретной ссылки — а почему собственно нет?
The God is real, unless declared integer.
Re[22]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 29.04.23 16:05
Оценка:
Здравствуйте, netch80, Вы писали:

R>>Другими словами, ты предлагаешь запретить привязывать константные ссылки к неконстантным объектам? Сомнительная идея как по мне.


N>Я такого у него не читал.


Правильно, поэтому я и написал "другими словами". Его слова были буквально такими:

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


Но разве из этого не следует, что константные ссылки на неконстантные объекты должны быть запрещены (в well-defined программе, разумеется)? Иначе каким образом можно обеспечить сформулированное требование?
--
Справедливость выше закона. А человечность выше справедливости.
Re[6]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 16:10
Оценка:
Здравствуйте, netch80, Вы писали:

N>1. Если src и dst это локальные переменные функции, и никто не берёт их адрес для каких-то целей (или делает это позже данного кода), то то, что я говорю, на них не распространяется.


А, ну это как действует компилятор с -fno-strict-aliasing, получается.

А если всё же
foo(&src);
while(*dst++=*src++);

?

N>2. А вот содержимое памяти по этим указателям — да, должен читать.


Это само собой.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[7]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 16:33
Оценка:
Здравствуйте, T4r4sB, Вы писали:

N>>1. Если src и dst это локальные переменные функции, и никто не берёт их адрес для каких-то целей (или делает это позже данного кода), то то, что я говорю, на них не распространяется.


TB>А, ну это как действует компилятор с -fno-strict-aliasing, получается.


Угу.

TB>А если всё же

TB>
TB>foo(&src);
TB>while(*dst++=*src++);
TB>

TB>?

Ну по идее в таком варианте можно соптимизировать, из соображений, что так как foo закончилась, а src локальная, и никто больше не зовётся, то можно сделать лучше.

А вот если например

foo(&src);
while(*dst++=*src++);
bar();


то уже сложнее, потому что foo() могла запомнить адрес src где-то ещё, а bar() его применить...
Если там внутри нет межнитевой синхронизации, и в цикле никого не зовём, о ком твёрдо не знаем, что он src не трогаем, то таки можно оптимизировать, вернув финальное значение src в указанную в &src память перед bar(). Если есть — то нельзя и этого.

На практике, что GCC, что Clang действуют по принципу — с момента взятия адреса локальной переменной она уже превращается в сущность того же рода, что полученная по указателю/ссылке или глобальная — и включаются все стандартные правила. До этого, сколько кода ни было бы, такого нет.
Приём простой и достаточно эффективный как для реальных случаев, усложнять тут наблюдение они не хотят.
The God is real, unless declared integer.
Re[23]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.04.23 16:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>Другими словами, ты предлагаешь запретить привязывать константные ссылки к неконстантным объектам? Сомнительная идея как по мне.


N>>Я такого у него не читал.


R>Правильно, поэтому я и написал "другими словами". Его слова были буквально такими:


R>

R>Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется!


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

Вызвали moo(a1) где void moo(const foo&a) — всё время жизни этой ссылки "a" компилятор предполагал бы, что объект, на который ссылается a, не меняется.

Но я, кажется, вижу, какие могут быть грабли. Пусть moo() тут сохранит эту ссылку куда-то ещё в долгосрочное хранилище, откуда его берёт какой-то другой код... можно ли компилятору предположить, что объект по ссылке не меняется, например, всё время жизни программы? Где-то надо провести границу, или давать это явно сделать кодеру.

R>Но разве из этого не следует, что константные ссылки на неконстантные объекты должны быть запрещены (в well-defined программе, разумеется)? Иначе каким образом можно обеспечить сформулированное требование?


Это слишком абстрактно и лучше рассматривать, как я описал выше.
The God is real, unless declared integer.
Re[24]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 29.04.23 16:47
Оценка:
Здравствуйте, netch80, Вы писали:

N>Но я, кажется, вижу, какие могут быть грабли. Пусть moo() тут сохранит эту ссылку куда-то ещё в долгосрочное хранилище, откуда его берёт какой-то другой код... можно ли компилятору предположить, что объект по ссылке не меняется, например, всё время жизни программы? Где-то надо провести границу, или давать это явно сделать кодеру.


ИМХО, подобные хотелки здорово оторваны от реальности. Более реальный вариант — стараться писать как можно более простой код, понятный как человеку, так и компилятору с оптимизатором.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 29.04.2023 17:00 rg45 . Предыдущая версия . Еще …
Отредактировано 29.04.2023 16:54 rg45 . Предыдущая версия .
Re[21]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 21:52
Оценка:
Здравствуйте, rg45, Вы писали:

R>Другими словами, ты предлагаешь запретить привязывать константные ссылки к неконстантным объектам?


Можно просто запретить одновременно обращаться к объекту по константной ссылке и менять его по мутабельной ссылке. А если такое случилось — считать что это УБ.
А что, вот руст так и сделал. Там правило есть: на объект запрещено иметь мутабельную и хотя бы 1 иммутабельную ссылку. И две мутабельные тоже запрещено иметь. То есть мутабельная ссылка должна быть уникальной. Правда там компилятор за всем следит и не получится это обойти, кроме как "сломать" всё при помощи unsafe. И да, в русте в коде, аналогичном моему, будет сделано именно одно чтение из памяти. Ну и мутировать глобалку он без unsafe не даст.

R>ИМХО, подобные хотелки здорово оторваны от реальности.


Ага, как и strict aliasing, переполнение знаковых итд. В языке нет механизма отслеживать нарушение этих правил. Даже санитайзер для проверки алиасинга до сих пор не запилили.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 29.04.2023 21:54 T4r4sB . Предыдущая версия .
Re[24]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 29.04.23 21:56
Оценка:
Здравствуйте, netch80, Вы писали:

N>Но я, кажется, вижу, какие могут быть грабли. Пусть moo() тут сохранит эту ссылку куда-то ещё в долгосрочное хранилище, откуда его берёт какой-то другой код...


Но ведь грабли с strict aliasing же ввели и не зассали.
А что касается гарантии, что содержимое константной ссылки никто не будет менять, то есть руст и его borrow checker. Там правило есть: на объект запрещено иметь мутабельную и хотя бы 1 иммутабельную ссылку. И две мутабельные тоже запрещено иметь. То есть мутабельная ссылка должна быть уникальной. Правда там компилятор за всем следит и не получится это обойти, кроме как "сломать" всё при помощи unsafe. И да, в русте в коде, аналогичном моему, будет сделано именно одно чтение из памяти. Ну и мутировать глобалку он без unsafe не даст.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[23]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 08:17
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Правильно, поэтому я и написал "другими словами". Его слова были буквально такими:


R>

R>Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется!


R>Но разве из этого не следует, что константные ссылки на неконстантные объекты должны быть запрещены (в well-defined программе, разумеется)? Иначе каким образом можно обеспечить сформулированное требование?


Все проблемы из этого и растут. Сначала напридумывают ненужных атрибутов. А потом когда они начинают конфликтовать придумывают костыли. Когда костыли не стыкуются придумывают несуществующие понятия и новые костыли. Где не могут найти решения добавляют очередной UB.
const — может быть только если данные лежат в ПЗУ или в памяти с запретом на запись. В C++ вместо того что бы явно решать задачу вечно какие-то обходные пути придумывают. Вместо того что бы сделать возможность явно сообщать компилятору о допущениях, используемых в программе, его заставляют об этом самому догадываться по косвенным признакам. В результате вместо нормального инструмента получаем минное поле. При этом мины заложенные ранее активируются постепенно, с увеличением версии стандарта языка.
Re[24]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 08:23
Оценка: +3
Здравствуйте, kov_serg, Вы писали:

_>Все проблемы из этого и растут. Сначала напридумывают ненужных атрибутов. А потом когда они начинают конфликтовать придумывают костыли. Когда костыли не стыкуются придумывают несуществующие понятия и новые костыли. Где не могут найти решения добавляют очередной UB.

_>const — может быть только если данные лежат в ПЗУ или в памяти с запретом на запись. В C++ вместо того что бы явно решать задачу вечно какие-то обходные пути придумывают. Вместо того что бы сделать возможность явно сообщать компилятору о допущениях, используемых в программе, его заставляют об этом самому догадываться по косвенным признакам. В результате вместо нормального инструмента получаем минное поле. При этом мины заложенные ранее активируются постепенно, с увеличением версии стандарта языка.

Это const — ненужный атрибут? Боюсь, найдется немало людей с противоположным мнениеем. И я в их числе. Вообще есть мнение, что const следовало бы сделать модификатором по умолчанию, а мутабельность прописывать явно.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 30.04.2023 9:03 rg45 . Предыдущая версия .
Re[25]: Когда это наконец станет defined behavior?
От: reversecode google
Дата: 30.04.23 08:41
Оценка: +1
https://github.com/compiler-devel/llvm-project/commit/cfd497fadb8bae4c5428f40ea50cfc760649afa4
был же const
никто не хочет юзать
Re[26]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 08:54
Оценка:
Здравствуйте, reversecode, Вы писали:

R>никто не хочет юзать


А вот здесь я бы не торопился делать обобщения. Репрезентативность выборки сомнительная, имхо.

P.S. У этого новшества есть серьезные проблемы с обратной совместимостью — это да. А вот на счет "никто не хочет"... Кто понимает, тот хочет!
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 30.04.2023 8:59 rg45 . Предыдущая версия . Еще …
Отредактировано 30.04.2023 8:58 rg45 . Предыдущая версия .
Re[26]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 30.04.23 09:00
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://github.com/compiler-devel/llvm-project/commit/cfd497fadb8bae4c5428f40ea50cfc760649afa4

R>был же const
R>никто не хочет юзать

Просто пишите на русте, там это есть)
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[25]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 09:16
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Это const — ненужный атрибут? Боюсь, найдется немало людей с противоположным мнениеем. И я в их числе. Вообще есть мнение, что const следовало бы сделать модификатором по умолчанию, а мутабельность прописывать явно.


Вы просто не стой колокольни смотрите. Сам по себе const не только не нужный, но даже вредный атрибут. Дело в том что тут происходит смешивание понятий. О чем говорит этот const в C++? Это некоторый метафизический атрибут, который сообщает что есть надежда что это фигня не может быть изменена. И это не физическое правило, а ментальное. Поэтому и возникают UB на поворотах. Если бы язык проектировался по нормальному, то модели данных и их представления и ограничения и допущения можно было бы описывать явно. А не смешивать всё в кучу.
Re[24]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 30.04.23 09:18
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>const — может быть только если данные лежат в ПЗУ или в памяти с запретом на запись


А как ты без const будешь выдавать ключи мапы, например? По копии? Или выдавать на них ссылку без "бесполезного" const и говорить "не меняйте их пажалуста, а то УБЭ случитсо". Впрочем слом распределения объектов по корзинам не считается УБ в том же русте, но С++ может поступить более продвинуто и сказать "компилятор предполагает что хеш определён правильно".
Или как ты без const будешь расшаривать ссылку на объект между несколькими потоками?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 30.04.2023 9:24 T4r4sB . Предыдущая версия .
Re[25]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 09:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, kov_serg, Вы писали:


_>>const — может быть только если данные лежат в ПЗУ или в памяти с запретом на запись


TB>А как ты без const будешь выдавать ключи мапы, например? По копии? Или выдавать на них ссылку без "бесполезного" const и говорить "не меняйте их пажалуста, а то УБЭ случитсо". Впрочем слом распределения объектов по корзинам не считается УБ в том же русте, но С++ может поступить более продвинуто и сказать "компилятор предполагает что хеш определён правильно".

TB>Или как ты без const будешь расшаривать ссылку на объект между несколькими потоками?

Атрибут const не мешает менять данные от слова совсем, зато порождает множество UB на ровном месте и лишний код.
Вы слишком много возлагаете на const. Его вставляет программист, а отвечать должен за это компилятор. То есть ограничение условное и компилятор не в силах за ним уследить в ряде ситуаций. В результате возникают чудеса.
Re[22]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 09:58
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Ага, как и strict aliasing, переполнение знаковых итд. В языке нет механизма отслеживать нарушение этих правил. Даже санитайзер для проверки алиасинга до сих пор не запилили.


Ну так может быть это и есть объяснение, почему один сценарий объявляется UB, а другой нет? В твоем примере
Автор: T4r4sB
Дата: 28.04.23
у компилятора нет возможности отследить, но есть возможность гарантировать правильный результат. Да, плата за эти гарантии — потери возможности оптимизации, но надежность программы всегда имела более высокий приоритет, чем оптимизация. В добавок ко всему еще и у программиста во многих случая есть возможность переписать код так, чтоб убить обоих зайцев — и надежность, и производительность.

P.S. Если рассматривать конкретно этот пример, то почему-то же программист написал "return l + a;", а не "return l + ll;". Вероятно, он знает, что после вызова функции bar значение объекта, адресуемого ссылкой "a", должно (или может) измениться и осознанно обрабатывает этот случай?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 30.04.2023 10:18 rg45 . Предыдущая версия . Еще …
Отредактировано 30.04.2023 10:17 rg45 . Предыдущая версия .
Отредактировано 30.04.2023 10:16 rg45 . Предыдущая версия .
Отредактировано 30.04.2023 10:11 rg45 . Предыдущая версия .
Отредактировано 30.04.2023 10:08 rg45 . Предыдущая версия .
Re[23]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 10:08
Оценка: :)
Здравствуйте, rg45, Вы писали:

R> есть возможность переписать код так, чтоб убить обоих зайцев — и надежность, и производительность.


Вспоминаем народную мудрость про зайцев:
"Погонишься за двумя зайцами — от обоих и получишь"
Re[21]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 10:15
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

TB>>Типа передали константную ссылку — значит компилятор вправе предполагать что содержимое не меняется!


ЕМ>Если объект создается константным — вправе, и вполне себе предполагает (например, если объект статический, и есть возможность разместить его в RO-секции). А если откуда-то просто приходит ссылка на уже существующий объект, то весь смысл const заключается лишь в запрете его изменения через данную ссылку.


Просто const тут многозначный атрибут и в разных ситуациях его трактуют по разному. Именно отсюда все беды. Объект который не меняется никогда это одно, объект не меняется пока вам его выдали другое, вам выдали копию и можете делать что хотите объёкт не пострадает третье, а вам рекомендуют не менять его это четвёртое.

ps: на x86 можно вполне использовать диапазон памяти который запрещено писать что бы гарантировать const. Например добавлять 2^60 к адресу и мапить туда всю память но в ro режиме. Всё равно физическая шина <=48бит.
Тогда при попытке записи в const либо ловим где и либо фиксируем и игнорируем либо фиксируем и выходим. Почему так не делают не понятно.
Отредактировано 30.04.2023 10:21 kov_serg . Предыдущая версия .
Re[26]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 30.04.23 11:05
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Атрибут const не мешает менять данные от слова совсем


Мешает, потому что навешивание mutable и всякие там const_cast заставляют испытывать муки совести задуматься, а не случайно же тут константность навешали.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[23]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 30.04.23 11:09
Оценка:
Здравствуйте, rg45, Вы писали:

R>В твоем примере
Автор: T4r4sB
Дата: 28.04.23
у компилятора нет возможности отследить, но есть возможность гарантировать правильный результат.


Как и в любой другой оптимизации, в которой компилятор закладывается то, что программист идеально внимательный и не пишет код, содержащий UB. Как в том же стрикт алиасинге, например — компилятор не может доказать что адреса не перекрываются, но он может работать в режиме -fno-strict-aliasing.

R>P.S. Если рассматривать конкретно этот пример, то почему-то же программист написал "return l + a;", а не "return l + ll;". Вероятно, он знает, что после вызова функции bar значение объекта, адресуемого ссылкой "a", должно (или может) измениться и осознанно обрабатывает этот случай?


Ну это ж упрощённый пример. А в реальном коде может так оказаться, что программист поленился закешировать в локалку какое-то более сложное выражение.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[26]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 11:11
Оценка: +3
Здравствуйте, kov_serg, Вы писали:

_>Атрибут const не мешает менять данные от слова совсем


Он уберегает программиста от случайного ошибочного изменения данных и в этом его главная миссия. Если программист использует const_cast, то он осознанно берет на себя ответственность за правомерность этих действий.
--
Справедливость выше закона. А человечность выше справедливости.
Re[24]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 11:14
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Ну это ж упрощённый пример. А в реальном коде может так оказаться, что программист поленился закешировать в локалку какое-то более сложное выражение.


Ну так кто ему виноват, что он поленился. Значит, запустит профайлер, увидит и исправит свою ошибку. Главное, что такая возможность у него есть в этом случае.
--
Справедливость выше закона. А человечность выше справедливости.
Re[25]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 30.04.23 11:42
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну так кто ему виноват, что он поленился. Значит, запустит профайлер, увидит и исправит свою ошибку. Главное, что такая возможность у него есть в этом случае.


Ну тогда и стрикт алиасинг не нужен, программист профайлером поймёт, где лишние чтения из памяти, закеширует всё по локалкам и ускорит прогу.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[27]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 13:00
Оценка: :))
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, kov_serg, Вы писали:


_>>Атрибут const не мешает менять данные от слова совсем


R>Он уберегает программиста от случайного ошибочного изменения данных и в этом его главная миссия. Если программист использует const_cast, то он осознанно берет на себя ответственность за правомерность этих действий.

И так для кого этот атрибут? Для компилятора или для программиста? При условии что вся ответственность,в любом случае по стандарту, сваливается на программиста.
В современном железе есть возможности гарантировать неизменность памяти, но нет возможности предсказать, то что наворотит компилятор полагаясь на своё понимание отсутствия UB в коде.
Re[21]: Когда это наконец станет defined behavior?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 30.04.23 13:08
Оценка:
Здравствуйте, netch80, Вы писали:

N>const для объекта как источник предположения, что он не будет меняться, очень полезен.


Ничуть не полезен. Предположение о том, что объект, переданный "снаружи", не будет меняться там же ("снаружи"), следует не из наличия const, а из отсутствия volatile. Предположение о том, что объект не будет меняться вообще, можно делать лишь тогда, когда он создан сразу с const, и в нем нет mutable-членов.
Re[28]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 30.04.23 13:08
Оценка:
Данная дискуссия не будет полной без обсуждения volatile. Погнали!
Re[26]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 14:57
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Ну тогда и стрикт алиасинг не нужен, программист профайлером поймёт, где лишние чтения из памяти, закеширует всё по локалкам и ускорит прогу.


Мне кажется, у тебя сложилось не совсем верное представление, для чего те или иные сценарии объявляются как UB. Вовсе не оптимизации первичны в этом деле. UB объявляетя в тех случаях, когда компилятор не может дать гарантий корректности работы программы. И только потом уже эти сценарии используются как возможность для оптимизаций.
--
Справедливость выше закона. А человечность выше справедливости.
Re[28]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 15:04
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>И так для кого этот атрибут? Для компилятора или для программиста?


Язык программирования нужен для программиста. Ваш К.О.
--
Справедливость выше закона. А человечность выше справедливости.
Re[29]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 30.04.23 15:19
Оценка:
Здравствуйте, rg45, Вы писали:

R>Язык программирования нужен для программиста. Ваш К.О.


Это тоже надо было программистам:
std::bless<T> renamed to std::start_lifetime_as<T>, mutable const, std::launder и особенныех функций типа malloc, realloc.
Re[24]: Когда это наконец станет defined behavior?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 30.04.23 15:21
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

_>const — может быть только если данные лежат в ПЗУ или в памяти с запретом на запись.


Смысл const вовсе не в том, чтобы "физически гарантировать" невозможность изменения данных. Это указание компилятору: "по моему замыслу, в этой функции объект не будет меняться, поэтому, если я вдруг попытаюсь это сделать, дай мне по рукам". То есть, оно не для того, чтобы не менялось, а для того, чтобы своевременно обнаружить попытки такого изменения, нарушающие замысел автора.

Наверное, стоило бы дать этому атрибуту более подходящее имя, но в C/C++ с этим всегда было плохо.

А для того, чтобы размещать данные в памяти, недоступной для записи, есть совершенно другие средства — на уровне и компилятора, и линкера, и ОС/железа.

_>Вместо того что бы сделать возможность явно сообщать компилятору о допущениях, используемых в программе, его заставляют об этом самому догадываться по косвенным признакам.


Да, это давняя беда C/C++ — "сделаем сам язык как можно более простым и лаконичным, чтобы все остальное написать на нем". В начале 70-х это было вполне оправдано, но уже в 90-х стало анахронизмом.

_>мины заложенные ранее активируются постепенно, с увеличением версии стандарта языка.


Во многом потому, что стандарт языка набивают в основном "вторичным продуктом", который реализован средствами самого языка, но где-то снаружи, предлагая это "просто использовать", не заморачиваясь пониманием того, как оно работает. А сама идеология языка осталась в в 70-х, максимум в 90-х, когда без понимания внутреннего устройства нормально писать на C/C++ было невозможно.

По уму, в язык надо бы добавить побольше различных атрибутов и правил, позволяющих программисту в явной форме объяснить компилятору особенности своего замысла. Но на этом не словишь хайпа. В условиях, когда большинство не использует даже максимального уровня предупреждений, мало кто станет переходить на новую версию только потому, что она позволяет лучше страховать себя от ошибок. А вот перейти на версию, которая поддерживает локальные функции или сопрограммы — запросто, ибо "лямбды и корутины — это круто, это тренд, от них все прутся, значит, и нам это надо".
Re[30]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 30.04.23 15:26
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Это тоже надо было программистам:

_>std::bless<T> renamed to std::start_lifetime_as<T>, mutable const, std::launder и особенныех функций типа malloc, realloc.

Вероятно. Если ты располагаешь доказательствами обратного, то выкладывай.
--
Справедливость выше закона. А человечность выше справедливости.
Re[27]: Когда это наконец станет defined behavior?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 30.04.23 16:13
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>навешивание mutable и всякие там const_cast заставляют испытывать муки совести задуматься, а не случайно же тут константность навешали.


Смысл mutable в том, чтобы с помощью const можно было защитить от изменения ключевые свойства объекта, позволив при этом честно меняться его второстепенным свойствам.

Простейший пример — объект имеет в составе критическую секцию, состояние которой при захвате всегда изменяется. Если функция, получившая константную ссылку на такой объект, захочет захватить его лишь для того, чтобы атомарно проверить несколько свойств, не изменяя их, она не сможет этого сделать без извращений, если не снабдить секцию атрибутом mutable.
Re[28]: Когда это наконец станет defined behavior?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 30.04.23 16:21
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>И так для кого этот атрибут? Для компилятора или для программиста?


Для того, чтобы они могли лучше понимать друг друга.

_>При условии что вся ответственность,в любом случае по стандарту, сваливается на программиста.


Именно поэтому я считаю, что любой серьезный язык должен иметь достаточное количество средств для того, чтобы программист мог донести до компилятора свои планы. Если компилятор что-то может вывести сам — это прекрасно, но лучше бы иметь это только по умолчанию, а при необходимости иметь возможность его поправить. И все, что может быть автоматизировано, должно быть автоматизировано. Раз компилятор "знает все" о том, что получится в результате компиляции, сам бог велел дать ему возможность знать еще и то, чего ожидает программист.

_>В современном железе есть возможности гарантировать неизменность памяти, но нет возможности предсказать, то что наворотит компилятор полагаясь на своё понимание отсутствия UB в коде.


Так не надо полагаться на const там, где нужна аппаратная неизменяемость. По крайней мере — понимать, в каких случаях компилятор может ее обеспечить, а в каких — реально это сделает.
Re[26]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 02.05.23 13:41
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://github.com/compiler-devel/llvm-project/commit/cfd497fadb8bae4c5428f40ea50cfc760649afa4

R>был же const
R>никто не хочет юзать
Ну почему же? Я бы использовал, тем более, что для таких случаев у меня всегда прописан const, но из-за обратной совместимости это вряд ли возможно.
И каждый день — без права на ошибку...
Re[31]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 02.05.23 13:49
Оценка:
Здравствуйте, rg45, Вы писали:

_>>std::bless<T> renamed to std::start_lifetime_as<T>, mutable const, std::launder и особенныех функций типа malloc, realloc.

R>Вероятно. Если ты располагаешь доказательствами обратного, то выкладывай.
Почему функциональность std::start_lifetime_as<T> и std::launder нельзя было бы повесить на reinterpret_cast<T> ?
И каждый день — без права на ошибку...
Re: Когда это наконец станет defined behavior?
От: Кодт Россия  
Дата: 02.05.23 13:52
Оценка:
Здравствуйте, Ip Man, Вы писали:

IM>Из p0593, который был принят в C++20:


IM>Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.


lifetime начинается с момента выделения памяти под объект типа implicitly created type, а делать реинтерпрет прямо сейчас или когда угодно позже — какая разница?

В пропозале другое сказано: невзирая на то, что у объекта может быть вырожденный деструктор, время жизни заканчивается после его вызова.
И вот тут возникает забавная дырка!

alignas(T) char buf[sizeof(T)];
T* obj = (T*)buf;

// placement new не нужен, потому что T у нас implicitly created
setup_something(obj);
process_something(obj);
write_some_data(buf);

std::destroy_at(obj);
// obj умер

read_some_data(buf);
// obj снова жив?
// или нужно явно сделать
obj = (T*)buf;

process_something(obj);
Перекуём баги на фичи!
Re[2]: Когда это наконец станет defined behavior?
От: σ  
Дата: 02.05.23 14:00
Оценка: +2
IM>>Из p0593, который был принят в C++20:

IM>>Однако я не нашёл в стандарте C++20 упоминания, что reinterpret_cast может начать lifetime объекта. Хотя malloc и memcpy теперь легальны с этой точки зрения, т.е. этот пропозал был включён в стандарт, но обошли reinterpret_cast.


К>lifetime начинается с момента выделения памяти под объект типа implicitly created type


Если такой объект создан. А создаётся он если это необходимо для придания программе определённого поведения.

К>а делать реинтерпрет прямо сейчас или когда угодно позже — какая разница?


Разница в том, что нужен launder вокруг reinterpret_cast. В примере в пропозале его нет. И пропозал не отменяет его необходимости.
Отредактировано 02.05.2023 14:08 σ . Предыдущая версия .
Re[32]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 02.05.23 14:01
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Почему функциональность std::start_lifetime_as<T> и std::launder нельзя было бы повесить на reinterpret_cast<T> ?


Я не понимаю, какое значение это имеет в данном контексте. Из этого как-то выводится, что const -- ненужный атрибут
Автор: kov_serg
Дата: 30.04.23
?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 02.05.2023 14:02 rg45 . Предыдущая версия .
Re[2]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 15:03
Оценка: :)
Здравствуйте, Кодт, Вы писали:

К>std::destroy_at(obj);

К>// obj умер

К>read_some_data(buf);

К>// obj снова жив?

Срочно нужна функция для проверки наличия души у объекта std::has_soul и изгнания демонов std::exorcise и библиотека стандартных обрядов <rituals>

Умер не умер какая разница, процессору фиолетово, там что биты переходят в Z состояние. Но компилятор надо ублажить иначе UB, а в случае UB компилятору позволено делать пакости, даже если на данной архитектуре никаких неоднозначностей не могло возникнуть. Имхо весь этот анонизм с присоединёнными сущностями к хорошему не приведёт. Если они нужны сделайте их явными и доступными по const_expr. А так в результате имеем разные данные по одинаковым указателям. И другие не наблюдаемые на железе чудеса, но которые компилятор не моргнув глазом воплощает в бинарный код.
Re[33]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 15:17
Оценка: -1
Здравствуйте, rg45, Вы писали:


R>Я не понимаю, какое значение это имеет в данном контексте. Из этого как-то выводится, что const -- ненужный атрибут
Автор: kov_serg
Дата: 30.04.23
?


Если это для программиста то чем
int const x[1];

Лучше
int const_x[1];


Корме того что налагает обязательства на компилятор и требует дополнительных функций для разных модификаторов.
Re[25]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 15:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>Это const — ненужный атрибут? Боюсь, найдется немало людей с противоположным мнениеем. И я в их числе. Вообще есть мнение, что const следовало бы сделать модификатором по умолчанию, а мутабельность прописывать явно.

Для это есть erlang где все переменные не мутабельные.
Re[2]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 02.05.23 16:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>lifetime начинается с момента выделения памяти под объект типа implicitly created type, а делать реинтерпрет прямо сейчас или когда угодно позже — какая разница?


Байты пришли по сети и сохранились в буфер. Можно считать, что память выделилась? При этом тип объекта к которому мы кастуем, может меняться в зависимости от заголовка (как в примере).
Re[3]: Когда это наконец станет defined behavior?
От: Ip Man Китай  
Дата: 02.05.23 16:23
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Умер не умер какая разница, процессору фиолетово, там что биты переходят в Z состояние.


Это C++ и с ним надо считаться. Чтобы было фиолетово, можно писать на ассемблере.
Re[34]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 02.05.23 16:24
Оценка:
Здравствуйте, kov_serg, Вы писали:


R>>Я не понимаю, какое значение это имеет в данном контексте. Из этого как-то выводится, что const -- ненужный атрибут
Автор: kov_serg
Дата: 30.04.23
?


_>Если это для программиста то чем

_>
_>int const x[1];
_>

_>Лучше
_>
_>int const_x[1];
_>


_>Корме того что налагает обязательства на компилятор и требует дополнительных функций для разных модификаторов.


Что-то мне все труднее и труднее отслеживаться связь между тезисами. Какова цель вообще нашей дискуссии — ты хочешь меня в чем-то убедить, или ты хочешь, чтоб я тебя в чем-то убедил?
--
Справедливость выше закона. А человечность выше справедливости.
Re[33]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 02.05.23 17:08
Оценка:
Здравствуйте, rg45, Вы писали:

BFE>>Почему функциональность std::start_lifetime_as<T> и std::launder нельзя было бы повесить на reinterpret_cast<T> ?

R>Я не понимаю, какое значение это имеет в данном контексте. Из этого как-то выводится, что
Автор: kov_serg
Дата: 30.04.23
?


Не обязательно это рассматривать в контексте "const -- ненужный атрибут".
Рассмотрите, пожалуйста, этот вопрос шире: зачем мне, как программисту, иметь отдельно reinterpret_cast<T>, std::start_lifetime_as<T> и std::launder<T>?
Почему reinterpret_cast<T> не может делать работу std::start_lifetime_as<T>?
Почему reinterpret_cast<T> не может делать работу std::launder<T>?

Другими словами, почему список здесь
нельзя дополнить пунктом
12) if a pointer p represents the address A of a byte in memory
— an object X is located at the address A
— X is within its lifetime
— the type of X is the same as T, ignoring cv-qualifiers at every level
— every byte that would be reachable through the result is reachable through p
then
reinterpret_cast<T>(p) returns a pointer to the same memory that p points to, but where the referent object is assumed to have a distinct lifetime and dynamic type
?

И почему нельзя добавить аналогичный пункт для std::start_lifetime_as ?

  гуглёж кажет такое
здесь

alignas(int) char data[sizeof(int)];
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
И каждый день — без права на ошибку...
Re[2]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 02.05.23 17:38
Оценка:
Здравствуйте, Кодт, Вы писали:


К>
К>alignas(T) char buf[sizeof(T)];
К>T* obj = (T*)buf;

К>// placement new не нужен, потому что T у нас implicitly created
К>

Удачи тебе с любым объектом, у которого есть внутренние инварианты. Например, с юником. В какой строке байтовый мусор из char[] превращается в валидный юник? Ну вот зануление указателя вот, в какой строке оно должно происходить?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[34]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 02.05.23 17:40
Оценка:
Здравствуйте, kov_serg, Вы писали:


_>Если это для программиста то чем

_>
_>int const x[1];
_>

_>Лучше
_>
_>int const_x[1];
_>


Тут по сути ничем. А вот даже для итерирования по сету нужно жёстко запретить программисту менять ключи. Если это можно сделать на этапе компиляции, то почему б этого не сделать.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[35]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 20:47
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Тут по сути ничем. А вот даже для итерирования по сету нужно жёстко запретить программисту менять ключи. Если это можно сделать на этапе компиляции, то почему б этого не сделать.

Что бы запретить программисту жестко менять ключи ему надо выдавать область памяти которую он физически не сможет поменять (read only) или копию (что бы изменения ни на что не повлияли).
А так он преобразует const в не const и алга. А то что компилятор пытается это делать избыточно и не нужно. Всё равно есть обходные пути. Я к тому что не хрен указателю T* присовывать свойства которых физически нет.
Если они нужны сделайте явно complex_pointer<T> со всеми необходимыми атрибутами (выравниванием, правилами доступа, наличием "благословения" и жезненной силы) и правилами преобразования. Храните их в compile_time в шаблонах наздоровье. Но с возможность с ними взаимодействовать.
Но нет делается тоже самое, но все атрибуты скрываются под ковёр в результате сложность всплавает в компиляторе который быстро соображает что это UB и можно поиздеваться над программистом (так как можно делать что удобнее).
То есть программист должен знать не как работает железо, а что задумывает компилятор и чего там еще эти стандартизаторы напридумывали в последнем издании. И чем дальше тем более наркоманские оторванные от реального мира конструкции получаются.

ps: Если разделить виртуальное адресное пространство примерно так. То можно делать настоящие константные указатели и не только. Которые физически будут ограничивать указатели. Благо в 64битных системах свободных адресных бит более чем дофига.
[memory          , npages] data вся достпная память программе
[memory+delta_ro , npages] замаплено на data только чтение (запись игнорируется)
[memory+delta_we , npages] тоже замаплено на data только вызывает исключение при попытке записи
[memory+delta_na , npages] при любом обращении вызывает исключение
Re[36]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 02.05.23 21:16
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>А так он преобразует const в не const и алга.


Не надо путать преднамеренную диверсию и невнимательность.
Так можно сказать что и руст ни от чего не защищает, ведь можно написать unsafe и алга.
Предполагается, что средний программист ХОЧЕТ писать безопасный безглючный код, но в силу человеческого фактора регулярно случайно косячит. Конечно, С++ программисты вовсе не такие, и никогда не ошибаются, если верить тому, что они про себя говорят , но мы будем умнее и не будем им верить.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[37]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 21:40
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Не надо путать преднамеренную диверсию и невнимательность.

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

TB>Так можно сказать что и руст ни от чего не защищает, ведь можно написать unsafe и алга.

Что самое интересное без алга не работает

TB>Предполагается, что средний программист ХОЧЕТ писать безопасный безглючный код, но в силу человеческого фактора регулярно случайно косячит.

Но стандарт разрешает компилятору верить что в коде который написал программист нет UB. То есть они никогда не косячат. И на основании этого ложного утверждения делает не вменяемые изменения в генерируемом коде. Иногда даже такие какие физически не возможны в принципе.

TB>Конечно, С++ программисты вовсе не такие, и никогда не ошибаются, если верить тому, что они про себя говорят , но мы будем умнее и не будем им верить.

Тут еще веселей правила постоянно меняются и дополняются.Так что то что раньше было норм и работало теперь лютое UB и надо помимо преобразования типа еще и благословение у компилятора выпрашивать. И программа обрастает обрядами и костылями.
Re[3]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 21:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Удачи тебе с любым объектом, у которого есть внутренние инварианты. Например, с юником. В какой строке байтовый мусор из char[] превращается в валидный юник? Ну вот зануление указателя вот, в какой строке оно должно происходить?

Что мешает объекту быть в не валидном состоянии и при этом не вызывать UB. Можно добавить методы валидации или даже коррекции ошибок, когда не валидные состояния меняются на ближайшие валидные.
Re[38]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 02.05.23 21:53
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>так что мешает в названии переменной говорить программисту не менять переменную, зачем дополнительный тип.


А ещё лучше чтоб компилятор давал предупреждения, если программист меняет переменные, у которых такое специальное название! Чтоб ревью автоматизировать. А если лучше если это будут не предупреждения, а ошибки!

_>Что самое интересное без алга не работает


Как и с const_cast.

_>Но стандарт разрешает компилятору верить что в коде который написал программист нет UB. То есть они никогда не косячат. И на основании этого ложного утверждения делает не вменяемые изменения в генерируемом коде. Иногда даже такие какие физически не возможны в принципе.

_>Тут еще веселей правила постоянно меняются и дополняются.Так что то что раньше было норм и работало теперь лютое UB и надо помимо преобразования типа еще и благословение у компилятора выпрашивать. И программа обрастает обрядами и костылями.

Ну сорян, сообщество С++ полно не очень вменяемых людей . И любимый заскок крестовиков — это неадекватная переоценка своей внимательности.

_>Что мешает объекту быть в не валидном состоянии и при этом не вызывать UB. Можно добавить методы валидации или даже коррекции ошибок, когда не валидные состояния меняются на ближайшие валидные.


И как ты провалидируешь юник, собранный из битового мусора? Ну в нём какой-то набор байт, который, возможно, какой-то указатель куда-то, и? Как ты поймёшь, что он валиден? В реальном юнике это постулируется тем, что мы вызвали конструктор и верим в то, что конструктор корректный.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[39]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 02.05.23 22:16
Оценка:
Здравствуйте, T4r4sB, Вы писали:
_>>Что мешает объекту быть в не валидном состоянии и при этом не вызывать UB. Можно добавить методы валидации или даже коррекции ошибок, когда не валидные состояния меняются на ближайшие валидные.

TB>И как ты провалидируешь юник, собранный из битового мусора? Ну в нём какой-то набор байт, который, возможно, какой-то указатель куда-то, и? Как ты поймёшь, что он валиден? В реальном юнике это постулируется тем, что мы вызвали конструктор и верим в то, что конструктор корректный.

Для начала можно просто контрольную сумму добавить. Во вторых так собирают POD объекты без указателей, умных объектов и виртуальных таблиц.
Re[26]: Когда это наконец станет defined behavior?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 03.05.23 08:17
Оценка:
Здравствуйте, kov_serg, Вы писали:

R>>Это const — ненужный атрибут? Боюсь, найдется немало людей с противоположным мнениеем. И я в их числе. Вообще есть мнение, что const следовало бы сделать модификатором по умолчанию, а мутабельность прописывать явно.

_>Для это есть erlang где все переменные не мутабельные.

И где полно жизнерадостных хаков против этого типа словаря процесса, ETS, соседних процессов — хранителей состояния по своему настроению, или даже просто саморекурсии с исправленными значениями... а так да, можно сказать, что не мутабельные
The God is real, unless declared integer.
Re[22]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 03.05.23 08:20
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Просто const тут многозначный атрибут и в разных ситуациях его трактуют по разному. Именно отсюда все беды.


Никаких бед нет — в каждой отельной ситуцации трактовка однозначна. Многие ключевые слова могут иметь различную трактовку, в зависимости от контекста использования: "const", "class", "typename", "using" и пр. Тебя же не смущает, что в следующих двух маленьких объявлениях ключевое слово "class" употреблено сразу в четырех(!) разных смыслах?

http://coliru.stacked-crooked.com/a/af659bbf7cbaefb0

enum class E;

template<template<class A> class B, class C&, E>
void foo();


И что, где тут беды? Если кто-то не знает как правильно трактовать то или иноее слово в том или ином случае, то это его персональная беда.
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 03.05.23 17:12
Оценка: -2 :))
Здравствуйте, watchmaker, Вы писали:

W>Только объект, что изнчально был const.


Ну хорошо

struct S {
    const int i;
};

void bar(const S& s);

int foo() {
    const S s{1};
    int i1 = s.i;
    bar(s);
    int i2 = s.i;
    return i1 + i2;
}



https://godbolt.org/z/fE3W1G6ss

Вот зачем там второе
mov     eax, DWORD PTR [rsp+12]

?

Константный объект с константным полем передаётся по константной ссылке!
Разве изменение такого объекта (через const_cast, placement_new итд) это не UB? Разве компилятор не вправе предположить, что после вызова bar в объекте по-прежнему останется единица?
Или тут внезапно случился конфликт высера стандартизаторов и реально существующей кодобазы, и компиляторы решили не наглеть?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: Когда это наконец станет defined behavior?
От: watchmaker  
Дата: 03.05.23 20:31
Оценка: 4 (1)
Здравствуйте, T4r4sB, Вы писали:

  quote
TB>
TB>struct S {
TB>    const int i;
TB>};

TB>void bar(const S& s);

TB>int foo() {
TB>    const S s{1};
TB>    int i1 = s.i;
TB>    bar(s);
TB>    int i2 = s.i;
TB>    return i1 + i2;
TB>}
TB>



TB>https://godbolt.org/z/fE3W1G6ss


TB>Вот зачем там второе

TB>
TB>mov     eax, DWORD PTR [rsp+12]
TB>

TB>?




TB>Константный объект с константным полем передаётся по константной ссылке!

TB>Разве изменение такого объекта (через const_cast, placement_new итд) это не UB?

Это будет UB.


TB> Разве компилятор не вправе предположить, что после вызова bar в объекте по-прежнему останется единица?



Конечно он может это сделать: https://godbolt.org/z/T5MG743aW

        pushq   %rax
        movl    $1, (%rsp)
        movq    %rsp, %rdi
        callq   bar(S const&)@PLT
        movl    $2, %eax
        popq    %rcx
        retq
Re[10]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 03.05.23 20:40
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>Конечно он может это сделать: https://godbolt.org/z/T5MG743aW


Проверил разные версии кланга, да, он явно продвинутее, чем гцц.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 03.05.2023 20:42 T4r4sB . Предыдущая версия .
Re[11]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 03.05.23 21:13
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Проверил разные версии кланга, да, он явно продвинутее, чем гцц.


Несомненно продвинутее
https://godbolt.org/z/EY73G4nMr
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 03.05.23 21:21
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Несомненно продвинутее

_>https://godbolt.org/z/EY73G4nMr

Закон исключённого третьего опровергли, отлично!
А вот теорему Ферма какой компилятор опроверг, гцц или кланг или оба?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[10]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 04.05.23 07:52
Оценка: :))
Здравствуйте, watchmaker, Вы писали:


W>Конечно он может это сделать: https://godbolt.org/z/T5MG743aW


Хаха убираем const в строке 8 и даже продвинутый кланг забоялся делать предположения о КОНСТантном поле структуры
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 04.05.23 08:24
Оценка: -1 :)
Здравствуйте, T4r4sB, Вы писали:

TB>Хаха убираем const в строке 8 и даже продвинутый кланг забоялся делать предположения о КОНСТантном поле структуры


И где тут "хаха"? Читай определение, что такое const object:

https://timsong-cpp.github.io/cppwp/basic.type.qualifier#1.1
https://timsong-cpp.github.io/cppwp/basic.type.qualifier#2

A const object is an object of type const T or a non-mutable subobject of a const object.

Except for array types, a compound type ([basic.compound]) is not cv-qualified by the cv-qualifiers (if any) of the types from which it is compounded.




После снятия константности с объекта "s", "i" перестал быть подобъектом константного объекта, а значит и сам перестал быть константным объектом. Следовательно и пункт, в котором декларируется неопределенное поведение, с этого момента на "i" не распространяется:

https://timsong-cpp.github.io/cppwp/dcl.type.cv#4

Any attempt to modify ([expr.ass], [expr.post.incr], [expr.pre.incr]) a const object (basic.type.qualifier) during its lifetime ([basic.life]) results in undefined behavior.

--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 04.05.2023 8:34 rg45 . Предыдущая версия . Еще …
Отредактировано 04.05.2023 8:25 rg45 . Предыдущая версия .
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 04.05.23 08:44
Оценка:
Здравствуйте, rg45, Вы писали:

R>После снятия константности с объекта "s", "i" перестал быть подобъектом константного объекта, а значит и сам перестал быть константным объектом.


Хм значит тут по ссылке фигню сказали:
https://stackoverflow.com/questions/66176720/why-introduce-stdlaunder-rather-than-have-the-compiler-take-care-of-it

Там в ответе https://stackoverflow.com/a/66178351 — как раз похожий пример. Константное поле неконстантного объекта.

Кроме того, там есть ссылка на документ, в котором приведен пример с placement new, где есть УБ, но по факту даже кланг боится убирать лишнее чтение из памяти

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0532r0.pdf
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 04.05.2023 8:46 T4r4sB . Предыдущая версия .
Re[13]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 04.05.23 11:34
Оценка:
Здравствуйте, T4r4sB, Вы писали:


R>>После снятия константности с объекта "s", "i" перестал быть подобъектом константного объекта, а значит и сам перестал быть константным объектом.


TB>Хм значит тут по ссылке фигню сказали:

TB>https://stackoverflow.com/questions/66176720/why-introduce-stdlaunder-rather-than-have-the-compiler-take-care-of-it

Я должен честно признаться — я не уверен в том, что сказал выше. Это на правах версии. В частности, я не вижу препятствий к тому, чтоб первую часть опрелеления "A const object is an object of type const T" отнести и к подобъекту в т.ч. На мой взгляд, формулировки оставляют желать лучшего в этом месте.
--
Справедливость выше закона. А человечность выше справедливости.
Re[12]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 04.05.23 11:36
Оценка:
Здравствуйте, rg45, Вы писали:

R>

R>A const object is an object of type const T or a non-mutable subobject of a const object.


R>

R>Except for array types, a compound type ([basic.compound]) is not cv-qualified by the cv-qualifiers (if any) of the types from which it is compounded.

R>После снятия константности с объекта "s", "i" перестал быть подобъектом константного объекта, а значит и сам перестал быть константным объектом. Следовательно и пункт, в котором декларируется неопределенное поведение, с этого момента на "i" не распространяется:
Это не так. Из того, что сам объект перестал быть константным не следует, что его подобъекты объявленные const перестали быть константными.
  Скрытый текст
#include <iostream>
struct S {
    const int i;
};

void bar(const S& s)
{
    std::cout << "const" << s.i << '\n';
}

void bar(S& s)
{
    std::cout << "non const" << s.i << '\n';
}

int foo() {
    const S s{1};
    bar(s); // s - const
    S x{2};
    bar(x); // x - non const 
    return 0;
}
int main() { foo(); }
И каждый день — без права на ошибку...
Re[13]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 04.05.23 11:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Это не так.


Охотно допускаю, что это не так. Но то, что ты пытаешься привести в качестве доказательства — это фигня на постном масле, а не доказательство. Константностью ссылок невозможно доказать константность объекта.
--
Справедливость выше закона. А человечность выше справедливости.
Re[14]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 04.05.23 13:55
Оценка:
Здравствуйте, rg45, Вы писали:

BFE>>Это не так.

R>Охотно допускаю, что это не так.
Это и есть "не так".

R> Но то, что ты пытаешься привести в качестве доказательства — это фигня на постном масле, а не доказательство.

Это не доказательство. это иллюстрация, что неконстантный объект может содержать константные данные и состоять только из константных данных.

R> Константностью ссылок невозможно доказать константность объекта.

Можно, так как неконстантная ссылка не может быть автоматически создана на константный объект.
Но зачем так сложно?
Вот это, естественно, не скомпилируется:
struct S { const int i; };
S x{2};
x.i = 3;

Чем не доказательство, что x.i — константный подобъект?
И каждый день — без права на ошибку...
Re[15]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 04.05.23 15:20
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>> Константностью ссылок невозможно доказать константность объекта.

BFE>Можно, так как неконстантная ссылка не может быть автоматически создана на константный объект.
BFE>Но зачем так сложно?
BFE>Вот это, естественно, не скомпилируется:
BFE>
BFE>struct S { const int i; };
BFE>S x{2};
BFE>x.i = 3;
BFE>

BFE>Чем не доказательство, что x.i — константный подобъект?

По этой логике, следующий фрагмент тоже можно пытаться выдать за доказательство константности объекта — это тоже не скомпилируется:

int i;
const int& r = i;
r = 3;


Ссылка на константный объект! А объект-то нифига не константный. Короче, фигня это все, а не доказательства.

Если тебе так уже приспичило что-то доказвать, то докажи, что пример ниже порождает неопределенное поведение, и обоснуй ссылками на стандарт:

struct S { const int i; };
S x{2};
const_cast<int&>(x.i) = 3;


А попутно было бы неплохо также ответить на вопрос
Автор: T4r4sB
Дата: 04.05.23
, почему компиляторы убирают оптимизацию при снятии константности с "x". Уж не потому ли, что определение констатного объекта, данное стандартом, допускает двусмысленное толкование?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 04.05.2023 15:42 rg45 . Предыдущая версия . Еще …
Отредактировано 04.05.2023 15:41 rg45 . Предыдущая версия .
Отредактировано 04.05.2023 15:33 rg45 . Предыдущая версия .
Отредактировано 04.05.2023 15:29 rg45 . Предыдущая версия .
Отредактировано 04.05.2023 15:24 rg45 . Предыдущая версия .
Re[16]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 04.05.23 16:51
Оценка: 12 (2)
Здравствуйте, rg45, Вы писали:

R> Уж не потому ли, что определение констатного объекта, данное стандартом, допускает двусмысленное толкование?


Я подозреваю, что если считать такое присвоение UB, то тогда, если верить статье https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0532r0.pdf, использование элемента вектора после очистки и пуша — это тоже UB, потому что компилятор может вывести, что адрес такого элемента совпадает с ранее использованным адресом по тому же индексу, и значит константные элементы не меняются.
Пример из статьи:
struct X {
  const int i;
  X(int _i) : i(_i) {}
  friend std::ostream& operator<< (std::ostream& os, const X& x) {
    return os << x.i;
  }
};
std::vector<X> v;
v.push_back(X(42));
v.clear();
v.push_back(X(77));
std::cout << v[0]; // undefined behavior



Если же НЕ считать такое присвоение UB, то тогда нихрена не понятно, зачем нужен std::launder, и в каких примерах он типа "убирает UB".

Выглядит всё так, будто авторы стандарта со своими UB опять трахнули в мозг сами себя.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[16]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 04.05.23 17:46
Оценка: 11 (1) +1
Здравствуйте, rg45, Вы писали:

R>По этой логике, следующий фрагмент тоже можно пытаться выдать за доказательство константности объекта — это тоже не скомпилируется:

R>
R>int i;
R>const int& r = i;
R>r = 3;
R>

R>Ссылка на константный объект! А объект-то нифига не константный. Короче, фигня это все, а не доказательства.
Ссылка — не объект.

R>Если тебе так уже приспичило что-то доказвать, то докажи, что пример ниже порождает неопределенное поведение, и обоснуй ссылками на стандарт:

R>
R>struct S { const int i; };
R>S x{2};
R>const_cast<int&>(x.i) = 3;
R>


С++23 n4944

9.2.9.2/4:

Any attempt to modify (7.6.19, 7.6.1.6, 7.6.2.3) a const object (6.8.5) during its lifetime (6.7.3) results in undefined behavior.


6.8.5/1.1:

A const object is an object of type const T or a non-mutable subobject of a const object.

И даже специальная заметка:
7.6.1.11/6:

[Note 2 : Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member
resulting from a const_cast that casts away a const-qualifier60 can produce undefined behavior (9.2.9.2). —end
note]

Так что формально это undefined behavior.
Что смущает-то?

R>А попутно было бы неплохо также ответить на вопрос
Автор: T4r4sB
Дата: 04.05.23
, почему компиляторы убирают оптимизацию при снятии константности с "x". Уж не потому ли, что определение констатного объекта, данное стандартом, допускает двусмысленное толкование?

Да мало ли может быть причин не относящихся к стандарту?
И каждый день — без права на ошибку...
Re[17]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 04.05.23 18:04
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Я подозреваю, что если считать такое присвоение UB, то тогда, если верить статье https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0532r0.pdf, использование элемента вектора после очистки и пуша — это тоже UB, потому что компилятор может вывести, что адрес такого элемента совпадает с ранее использованным адресом по тому же индексу, и значит константные элементы не меняются.

В статье про время жизни объектов, а не про изменение константного объекта во время его жизни.

TB>Выглядит всё так, будто авторы стандарта со своими UB опять трахнули в мозг сами себя.

Согласен.
И каждый день — без права на ошибку...
Re[17]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 04.05.23 18:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>6.8.5/1.1:

BFE>

BFE>A const object is an object of type const T or a non-mutable subobject of a const object.

BFE>И даже специальная заметка:
BFE>7.6.1.11/6:
BFE>

BFE>[Note 2 : Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member
BFE>resulting from a const_cast that casts away a const-qualifier60 can produce undefined behavior (9.2.9.2). —end
BFE>note]

BFE>Так что формально это undefined behavior.
BFE>Что смущает-то?

Согласен, выглядит убедительно.

BFE>Да мало ли может быть причин не относящихся к стандарту?


Хочется ясности.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 04.05.2023 18:20 rg45 . Предыдущая версия .
Re[11]: Когда это наконец станет defined behavior?
От: σ  
Дата: 04.05.23 22:32
Оценка:
W>>Конечно он может это сделать: https://godbolt.org/z/T5MG743aW

TB>Хаха убираем const в строке 8 и даже продвинутый кланг забоялся делать предположения о КОНСТантном поле структуры


void bar(const S& s) может быть определена как
void bar(const S& s)
{
    ::new (&s) S { /* новое значение для s.i */ };
}
?
Re[12]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 05.05.23 06:57
Оценка:
Здравствуйте, σ, Вы писали:

σ>void bar(const S& s) может быть определена как

σ>
σ>void bar(const S& s)
σ>{
σ>    ::new (&s) S { /* новое значение для s.i */ };
σ>}
σ>
?


Не знаю, а с точки зрения стандарта и UB так можно?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[13]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 08:03
Оценка:
σ>>void bar(const S& s) может быть определена как
σ>>
σ>>void bar(const S& s)
σ>>{
σ>>    ::new (&s) S { /* новое значение для s.i */ };
σ>>}
σ>>
?


TB>Не знаю, а с точки зрения стандарта и UB так можно?


Можно.
Re[14]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 08:15
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>void bar(const S& s) может быть определена как

σ>>>
σ>>>void bar(const S& s)
σ>>>{
σ>>>    ::new (&s) S { /* новое значение для s.i */ };
σ>>>}
σ>>>
?


TB>>Не знаю, а с точки зрения стандарта и UB так можно?


σ>Можно.


Если bar получает константную ссылку на S, то оно вообще не должно скомпилироваться: https://wandbox.org/permlink/QmsGOIVldZJHwUCM
Re[15]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 08:18
Оценка:
S>Если bar получает константную ссылку на S, то оно вообще не должно скомпилироваться: https://wandbox.org/permlink/QmsGOIVldZJHwUCM

Ой-вей, сложно кастануть? Я типа псевдокода запостил. Ещё бы докопался что #include <new> не написал.
Re[16]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 08:27
Оценка:
Здравствуйте, σ, Вы писали:

S>>Если bar получает константную ссылку на S, то оно вообще не должно скомпилироваться: https://wandbox.org/permlink/QmsGOIVldZJHwUCM


σ>Ой-вей, сложно кастануть? Я типа псевдокода запостил.


Как только мы выполняем const_cast, мы вступаем на поле UB.

Соответственно, ответом на вопрос "Не знаю, а с точки зрения стандарта и UB так можно?" вряд ли может быть "можно".
Re[17]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 08:29
Оценка:
S>>>Если bar получает константную ссылку на S, то оно вообще не должно скомпилироваться: https://wandbox.org/permlink/QmsGOIVldZJHwUCM

σ>>Ой-вей, сложно кастануть? Я типа псевдокода запостил.


S>Как только мы выполняем const_cast, мы вступаем на поле UB.


Подробнее.
Re[14]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 05.05.23 08:30
Оценка:
Здравствуйте, σ, Вы писали:

σ>Можно.


Тогда я не понимаю эту фигню с лаундером. В каком случае он нужен?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[18]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 08:37
Оценка:
Здравствуйте, σ, Вы писали:

S>>>>Если bar получает константную ссылку на S, то оно вообще не должно скомпилироваться: https://wandbox.org/permlink/QmsGOIVldZJHwUCM


σ>>>Ой-вей, сложно кастануть? Я типа псевдокода запостил.


S>>Как только мы выполняем const_cast, мы вступаем на поле UB.


σ>Подробнее.


Внутри bar неизвестно, передали ли в bar константную ссылку на константный объект или на неконстантный. Соответственно, когда мы в bar делаем const_cast и снимаем константность, то мы можем оказаться в ситуации, когда получили ссылку на реально константный объект, сняли с него константность и получили UB.
Re[15]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 08:38
Оценка:
σ>>Можно.

TB>Тогда я не понимаю эту фигню с лаундером. В каком случае он нужен?


https://timsong-cpp.github.io/cppwp/n4868/ptr.launder#example-1
(раньше ограничения были строже, ср. с https://timsong-cpp.github.io/cppwp/n4659/ptr.launder#5)
Re[19]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 08:46
Оценка:
S>когда мы в bar делаем const_cast и снимаем константность, то мы можем оказаться в ситуации

А можем не оказаться.
Re[20]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 08:50
Оценка:
Здравствуйте, σ, Вы писали:

S>>когда мы в bar делаем const_cast и снимаем константность, то мы можем оказаться в ситуации


σ>А можем не оказаться.


О том и речь, что ответ "может" не совсем точен. По хорошему, он должен быть дополнен оговорками.
Re[21]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 05.05.23 08:56
Оценка:
Здравствуйте, so5team, Вы писали:

σ>>А можем не оказаться.


S>О том и речь, что ответ "может" не совсем точен. По хорошему, он должен быть дополнен оговорками.


Как я понял, это "можно" следует относить к конткретному примеру, когда мы хаха, убираем const в строке 8
Автор: T4r4sB
Дата: 04.05.23
. Хотя, мой стеклянный шар частенько подводит меня в последнее время.

P.S. И это отвечает на вопрос, почему компиляторы убирают оптимизацию при снятии константности с объекта "s".
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 05.05.2023 9:11 rg45 . Предыдущая версия . Еще …
Отредактировано 05.05.2023 8:57 rg45 . Предыдущая версия .
Re[22]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 09:13
Оценка:
Здравствуйте, rg45, Вы писали:

S>>О том и речь, что ответ "может" не совсем точен. По хорошему, он должен быть дополнен оговорками.


R>Как я понял, это "можно" следует относить к конткретному примеру, когда мы хаха, убираем const в строке 8
Автор: T4r4sB
Дата: 04.05.23
. Хотя, мой стеклянный шар частенько подводит меня в последнее время.


Вероятно.

Я думаю, что здесь можно (нужно?) смотреть на происходящее с двух точек зрения:

1) снаружи bar экземпляр типа S не константен, следовательно, при передаче его в bar можно ожидать чего угодно, в том числе и const_cast с последущей модификаций. Что не позволяет оптимизатору делать какие-то предположения;

2) внутри bar мы можем предполагать, что получили ссылку на неконстантный объект и что const_cast безопасен. Но гарантий нет.

Соответственно, как только внутри bar появляется const_cast, так у нас появляются и шансы нарваться на UB.
Re[23]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 05.05.23 09:20
Оценка:
Здравствуйте, so5team, Вы писали:

S>Соответственно, как только внутри bar появляется const_cast, так у нас появляются и шансы нарваться на UB.


В данном сценарии то, что происходит внутри bar — это откровенный говнокод. Но при компиляции внешнего кода, который вызывает bar, компилятор видит, что, даже если подобный говнокод имеет место быть, то он не приведет к UB. Значит, компилятор обязан корректно обработать в т.ч. и этот сценарий.
--
Справедливость выше закона. А человечность выше справедливости.
Re[24]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 09:29
Оценка:
Здравствуйте, rg45, Вы писали:

R>В данном сценарии то, что происходит внутри bar — это откровенный говнокод.


В связи с тем, что можно прочитать по ссылке от ув.σ (https://timsong-cpp.github.io/cppwp/n4868/ptr.launder#example-1):
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const
const int b = p->n;                 // undefined behavior
const int c = std::launder(p)->n;   // OK

я уже не могу позволить себе быть столь категоричным.

Меня даже больше интересует, а не нужно ли после возвращения из bar вот здесь:
int foo() {
    const S s{1};
    int i1 = s.i;
    bar(s);
    int i2 = s.i; // (1)
    return i1 + i2;
}

сделать std::launder в точке (1). Поскольку lifetime для объекта s закончился внутри bar...
Re[25]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 05.05.23 09:34
Оценка:
Здравствуйте, so5team, Вы писали:


R>>В данном сценарии то, что происходит внутри bar — это откровенный говнокод.


S>В связи с тем, что можно прочитать по ссылке от ув.σ (https://timsong-cpp.github.io/cppwp/n4868/ptr.launder#example-1):


Говнокод в том смысле, что внутри функции bar действительно может порождаться UB. Мы же не видим места, откуда нас вызвали и ничего не знаем о константности объекта, ссылку на который нам передали. В одном случае UB может не быть, а в другом может быть. Приличные функции таких фортелей себе не позволяют.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 05.05.2023 9:38 rg45 . Предыдущая версия . Еще …
Отредактировано 05.05.2023 9:37 rg45 . Предыдущая версия .
Re[25]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 10:42
Оценка:
S>Меня даже больше интересует, а не нужно ли

Не нужно.
Re[18]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 05.05.23 10:49
Оценка: 11 (1) +1
Здравствуйте, rg45, Вы писали:

R>Хочется ясности.

Ссылка на p0532r0.pdf приведённая T4r4sB
Автор: T4r4sB
Дата: 04.05.23
многое проясняет:
Константный объект не может (без UB) быть изменён пока объект жив, но жизнь константного объекта можно закончить (если он подобъект неконстантного объекта), а на его месте создать новый объект с другим значением. (Поэтому в стандарте есть оговорка "during its lifetime").
Компилятору сложно отследить пересоздание константного объекта из-за того, что могут быть использованы самописные алокаторы. Проблема усугубляется тем, что требования к аллокаторам плохо совместимы с требованиями к placment new (хотя для меня этот вопрос до конца не ясен).
В целом получается, что есть много старого кода формально с UB и это мешает оптимизации, в том числе при вызове виртуальных функций. Причём UB не удаётся убрать правками стандарта.
И каждый день — без права на ошибку...
Re[26]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 10:57
Оценка:
Здравствуйте, σ, Вы писали:

S>>Меня даже больше интересует, а не нужно ли


σ>Не нужно.


А чем обсуждаемая ситуация:
void bar(const S & s) {
    new(const_cast<S&>(&s)) S{0};
}
 
int foo() {
    S s{1};
    int i1 = s.i;
    bar(s);
    int i2 = s.i; // (1)
    return i1 + i2;
}


отличается от примера, приведенного вот здесь: https://miyuki.github.io/2016/10/21/std-launder.html , а именно:
struct A {
  virtual int f();
};

struct B : A {
  virtual int f() { new (this) A; return 1; }
};

int A::f() { new (this) B; return 2; }

int h() {
  A a;
  int n = a.f();
  int m = std::launder(&a)->f();
  return n + m;
}


?
Re[27]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 16:57
Оценка: 6 (1)
S>>>Меня даже больше интересует, а не нужно ли

σ>>Не нужно.


S>А чем обсуждаемая ситуация:

S>
void bar(const S & s) {
    new(const_cast<S&>(&s)) S{0};
}
 
int foo() {
    S s{1};


Так, стоп. В сообщении про нужно/не нужно
Автор: so5team
Дата: 05.05.23
в коде const S s{1};
Впрочем, на ответ «не нужно» это не влияет.

S>отличается от примера, приведенного вот здесь: https://miyuki.github.io/2016/10/21/std-launder.html


Тем, что тип объекта не меняется
Re[28]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 05.05.23 18:24
Оценка:
Здравствуйте, σ, Вы писали:

S>>А чем обсуждаемая ситуация:

S>>
σ>void bar(const S & s) {
σ>    new(const_cast<S&>(&s)) S{0};
σ>}
 
σ>int foo() {
σ>    S s{1};
σ>


σ>Так, стоп. В сообщении про нужно/не нужно
Автор: so5team
Дата: 05.05.23
в коде const S s{1};


Так ведь если в foo() стоит const S s{1}, то изменение его в bar -- это UB?
Или константные объекты разрешено менять через placement new?

S>>отличается от примера, приведенного вот здесь: https://miyuki.github.io/2016/10/21/std-launder.html


σ>Тем, что тип объекта не меняется


Но в примере из стандарта:
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const
const int b = p->n;                 // undefined behavior
const int c = std::launder(p)->n;   // OK

тип объекта не меняется, но launder звать нужно.
Re[29]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 05.05.23 18:31
Оценка:
Здравствуйте, so5team, Вы писали:

S>Так ведь если в foo() стоит const S s{1}, то изменение его в bar -- это UB?

S>Или константные объекты разрешено менять через placement new?

Думаю, это UB, без вариантов: https://timsong-cpp.github.io/cppwp/dcl.type.cv#4
--
Справедливость выше закона. А человечность выше справедливости.
Re[29]: Когда это наконец станет defined behavior?
От: σ  
Дата: 05.05.23 18:38
Оценка: 12 (1)
S>Так ведь если в foo() стоит const S s{1}, то изменение его в bar -- это UB?
S>Или константные объекты разрешено менять через placement new?

https://timsong-cpp.github.io/cppwp/n4868/basic.life#10

S>>>отличается от примера, приведенного вот здесь: https://miyuki.github.io/2016/10/21/std-launder.html


σ>>Тем, что тип объекта не меняется


S>Но в примере из стандарта:

S>
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const
const int b = p->n;                 // undefined behavior
const int c = std::launder(p)->n;   // OK

S>тип объекта не меняется, но launder звать нужно.

https://timsong-cpp.github.io/cppwp/n4868/basic.life#8.3
Re[35]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 11.05.23 09:36
Оценка:
Здравствуйте, rg45, Вы писали:

R>ты хочешь меня в чем-то убедить


Попробую сформулировать претензии к const
1. этот модификатор создаёт дополнительный тип. На ровном месте число сущностей удваивается, а в случае контейнеров может и учетверяться и так далее. Для их обработки приходится писать разные методы
2. сам по себе он не гарантирует неизменность данных. в некоторых случаях даже нет возможности это отловить
3. очень узкоспециализированный (пытается описать только неизменность)
4. заставляет компилятор заниматься ненужным анализом и творить чудеса UB-строения
В то время как вместо этого модификатора нужны языковые конструкции которые описывают инварианты структур(классов) которые можно проверять при отладке и выявить их нарушения, а в релизе полагать что это заведомо выполняется в любых ситуациях и не проверять. При этом какие-то инварианты могут выполняться всегда (a=b-c или a<=b<=c ...), а какие-то при входе в метод и при выходе из него. Т.е. функция может нарушать инварианты локально но по выходу обязуется из восстановить.
Например инвариант неизменность переменной (аля const) или упорядоченность по возрастанию или то что данные удовлетворяют каким-то особым правилам куча, все поля валидны, бинарное дерево с высотами веток отличающимися не более чем на единицу или же граф без циклов или то что время выполнения будет ограничено и т.п. Более того ряд функций могут явно не соблюдать эти инварианты, но это тоже должно быть указано явно.
Re[36]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 11.05.23 20:24
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>1. этот модификатор создаёт дополнительный тип. На ровном месте число сущностей удваивается, а в случае контейнеров может и учетверяться и так далее. Для их обработки приходится писать разные методы


Не согласен. Сам по себе модификатор const не вынуждает писать дополнительные методы. Он ДАЕТ ВОЗМОЖНОСТЬ программисту предоставить разные версии функций-членов для константного и неконстантного объектов — только в том случае, если это нужно! Конечно, в каких-то простейших случаях могут возникать похожие на вид-функции члены, которые выглядят как дублирование, но это очень поверхностный взгляд, это во-первых. Во-вторых, необходимость создания разных методов не является ни общим случаем, ни, тем более единственным — все зависит от семантики и дизайна класса. Например, во многих случаях бывает достаточно одной только версии — константной. Кроме того никто не запрещает константным версиям возвращать неконстантные указатели и ссылки. Как пример — все методы доступа к данным умных указателей стандартной библиотеки: get(), operator*, operator-> и пр. — все эти методы существуют только в одном варианте — в константном, а ссылки и указатели возвращают в соответствии с типом указателя. Если у тебя регулярно возникает необходимость определения всех возможных комбинаций const/volatile/lvalue-/rvalue-reference, нужных и ненужных, то, возможно, у тебя какие-то системные проблемы с составлением дизайна. По этому пункту ты меня не убедил.

_>2. сам по себе он не гарантирует неизменность данных. в некоторых случаях даже нет возможности это отловить


В каких-то случаях гарантирует (в well-formed программе), если модификатор относится непосредственно к объекту. В каких-то случаях, если модификатор пришел со ссылкой, у него просто другая семантика — но он является средством выдачи прав на чтение/запись. То, что он не гарантирует неизменности, не означает, что он бесполезен. По этому пункту тоже не убедил.

_>3. очень узкоспециализированный (пытается описать только неизменность)


Так так и должно быть — const ни на что, кроме константности влиять и не должен. Опять не убедил.


_>4. заставляет компилятор заниматься ненужным анализом и творить чудеса UB-строения


Ну вот, опять "заставляет". Не "заставляет", а "дает возможность" — для оптимизаций. И оптимизации — дело добровольное — зависят исключительно от воли разработчиков компилятора.

Дальше вообще какая-то фантастика пошла. Не убедил ни по одному пункту.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 11.05.2023 20:43 rg45 . Предыдущая версия . Еще …
Отредактировано 11.05.2023 20:41 rg45 . Предыдущая версия .
Отредактировано 11.05.2023 20:27 rg45 . Предыдущая версия .
Re[37]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 11.05.23 21:36
Оценка:
Здравствуйте, rg45, Вы писали:

R>Не согласен. Сам по себе модификатор const не вынуждает писать дополнительные методы, а дает возможность программисту предоставить разные версии функций-членов для константного и не константного объектов — только в том случае, если это нужно!

Это не возможность, а обязанность. Как только они появляются то выясняется что нужно.
Не изменность данных может быть разной как по времени так и по форме.
Неизменность чего либо не обязательно неизменность участка памяти. Например одно и тоже целое число может быть представлено в разном виде но при этом оставаться этим же числом. Или более сложные формы инвариантов которые поддерживаются при работе программы.

R>Конечно, в каких-то простейших случаях могут возникать похожие на вид-функции члены, которые выглядят как дублирование, но это очень поверхностный взгляд, это во-первых.

Если кто-то обрабатывает const T& то сразу появляютcя методы ()const

R>Во-вторых, необходимость создания разных методов не является ни общим случаем, ни, тем более единственным — все зависит от семантики и дизайна класса.

R>Например, во многих случаях бывает достаточно одной только версии — константной.
Например метод size() должен быть константным или не обязательно?

R>если модификатор относится непосредственно к объекту.

А можно попросить не модифицировать только часть объекта или массива? А почему?

R>если модификатор пришел со ссылкой, у него просто другая семантика — но он является средством выдачи прав на чтение/запись.

Нафига эти церемонии в виде прав, тогда уж лучше токен на доступ приходит.

R>Так так и должно быть — const ни на что, кроме константности влиять и не должен. Опять не убедил.


Простой пример передали вам массив и просят его не менять. Можно сделать по разному
1. запретить любые записи в этот массив
2. в процессе работы функции меняем данные, но по выходу возвращаем в исходное состояние
В каждом варианте возможны разные виды оптимизаций, но d с++ только вар 1 с оговорками

R>Ну вот, опять "заставляет". Не "заставляет", а "дает возможность".

Нет когда без этого не собирается и обязательно учитывать константность, то это заставляет.

R>Дальше вообще какая-то фантастика пошла.

Какая фантастика https://tour.dlang.org/tour/en/gems/contract-programming
Re[38]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 12.05.23 07:02
Оценка:
Здравствуйте, kov_serg, Вы писали:

Ты думаешь, если ты повторишь одно и тоже несколько раз, это зазвучит убедительнее?
--
Справедливость выше закона. А человечность выше справедливости.
Re[39]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 08:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ты думаешь, если ты повторишь одно и тоже несколько раз, это зазвучит убедительнее?

возможно я просто хреново объясняю
const в c++ это просто частный инвариант причем который воспринимается по разному в разных ситуациях, что приводит к противоречиям (которые позволено компилятору, благодаря стандартизаторам, трактовать слишком вольно)
Re[40]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 08:58
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

R>>Ты думаешь, если ты повторишь одно и тоже несколько раз, это зазвучит убедительнее?

_>возможно я просто хреново объясняю
_>const в c++ это просто частный инвариант причем который воспринимается по разному в разных ситуациях, что приводит к противоречиям (которые позволено компилятору, благодаря стандартизаторам, трактовать слишком вольно)

Тем не менее, он играет важную роль. Например, когда мы видим:
class some_application_domain_type {...};

void do_something(const some_application_domain_type & o);

То мы понимаем, что объект в do_something отдается не для изменения (и что сам do_something не претендует на его изменение).

Да, здесь есть ряд оговорок и под капотом может быть разное, но по большей части такие аннотации делают код проще.
При программировании на Java, Ruby или Python, где подобного понятия константной ссылки нет, разбираться с кодом сложнее, т.к. изначально не ясно, будет ли do_something менять переданные ему аргументы или нет.

Тогда как в D константы (и не только) есть и там намного проще.

Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?

Неужели просто доверять программисту?
Re[41]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 09:29
Оценка:
Здравствуйте, so5team, Вы писали:

S>Тем не менее, он играет важную роль. Например, когда мы видим:

S>
S>class some_application_domain_type {...};

S>void do_something(const some_application_domain_type & o);
S>

S>То мы понимаем, что объект в do_something отдается не для изменения (и что сам do_something не претендует на его изменение).

S>Да, здесь есть ряд оговорок и под капотом может быть разное, но по большей части такие аннотации делают код проще.

S>При программировании на Java, Ruby или Python, где подобного понятия константной ссылки нет, разбираться с кодом сложнее, т.к. изначально не ясно, будет ли do_something менять переданные ему аргументы или нет.

S>Тогда как в D константы (и не только) есть и там намного проще.


S>Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?


S>Неужели просто доверять программисту?

Нет просто описывать это отдельно от типа.

void do_something(some_application_domain_type & o) where o is immutable;
Re[42]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 09:52
Оценка:
Здравствуйте, kov_serg, Вы писали:

S>>Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?


S>>Неужели просто доверять программисту?

_>Нет просто описывать это отдельно от типа.

_>void do_something(some_application_domain_type & o) where o is immutable;


Вы реально видите разницу между
void do_something(const some_application_domain_type & o);

и
void do_something(some_application_domain_type & o) where o is immutable;




Как по мне, так это все тот же фрагмент автопортрета Фаберже, но даже и не в профиль, а через неподходяшее отверстие.
Re[41]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 10:03
Оценка:
Здравствуйте, so5team, Вы писали:

s> При программировании на Java

s> Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?
Принято вводить интерфейсы. Это позволяет определять любые группы методов обладающих определённым свойством, в том числе и константностью.
Как я понимаю, в плюсах интерфейс — это виртуальный вызов, дорого. Поэтому обычно не используется.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[42]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 10:08
Оценка:
Здравствуйте, ·, Вы писали:

s>> Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?

·>Принято вводить интерфейсы. Это позволяет определять любые группы методов обладающих определённым свойством, в том числе и константностью.

И как такое свойство как "константность" проверяется в Java?

·>Как я понимаю, в плюсах интерфейс — это виртуальный вызов, дорого. Поэтому обычно не используется.


Вряд ли сильно дороже чем в Java

Upd. Константность в C++ появилась раньше, чем Java 1.0 вышла в свет.
Отредактировано 12.05.2023 10:12 so5team . Предыдущая версия .
Re[43]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 10:20
Оценка:
Здравствуйте, so5team, Вы писали:

S>Вы реально видите разницу между

S>
void do_something(const some_application_domain_type & o);

S>и
S>
void do_something(some_application_domain_type & o) where o is immutable;


S>


S>Как по мне, так это все тот же фрагмент автопортрета Фаберже, но даже и не в профиль, а через неподходяшее отверстие.


Разница огромна. Вместо дополнительного типа у нас требования (ограничения) которые должна соблюдать функция. Они могут описывать разные виды ограничений.
Например:
void do_something(int o[3]) where o[1] is immutable; -- запрещено менять o[1]

void do_something(int o[3]) where o[1] is keep same; -- можно менять, но по выходу должно быть тоже значение что и при входе

void heap_op(int x[],int n) where x[0..n) is heap; -- на входе куча и на выходе должна быть куча x[k]<=x[2*k+{1,2}]

void do_something(some_type &o) where o keep up some_type.invariants;
Re[44]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 10:23
Оценка:
Здравствуйте, kov_serg, Вы писали:

S>>Как по мне, так это все тот же фрагмент автопортрета Фаберже, но даже и не в профиль, а через неподходяшее отверстие.


_>Разница огромна.


Да, оказывается вы вещаете не о C++, а о каких-то своих фантазиях.

Этот ваш гипотетический язык пока только в ваших мечтах существует или уже есть какой-то работающий прототип?
Re[43]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 10:26
Оценка:
Здравствуйте, so5team, Вы писали:

s>>> Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?

S>·>Принято вводить интерфейсы. Это позволяет определять любые группы методов обладающих определённым свойством, в том числе и константностью.
S>И как такое свойство как "константность" проверяется в Java?
В смысле имеет ли компилятор модель константности? Нет. Просто делается на уровне дизайна, т.е. тоже является частью системы типов. Иными словами, неясно почему именно константность должна быть каким-то особым свойством, которое должен проверять копилятор.
Скажем, "этот метод может только добавлять элементы в конец списка", а "этот метод может только читать" — это всё определённый контракты.

В любом случае это же просто ментальная пометка для человеков, всего лишь: "не претендует на его изменение". Ведь всё равно "do_something" может снять константность и навредить, или mutable может быть. Т.е. const это по сути контракт для человека, как и interface. Никакой разницы для машины нет.

S>·>Как я понимаю, в плюсах интерфейс — это виртуальный вызов, дорого. Поэтому обычно не используется.

S>Вряд ли сильно дороже чем в Java
В java есть virtual call elimination. В итоге виртуальные методы могут даже инлайниться. Или
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[44]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 10:34
Оценка:
Здравствуйте, ·, Вы писали:

S>>И как такое свойство как "константность" проверяется в Java?

·>В смысле имеет ли компилятор модель константности?

Да

·>Нет.


Оттож.

·>Просто делается на уровне дизайна, т.е. тоже является частью системы типов.


Иными словами "мамой клянусь"

·>Иными словами, неясно почему именно константность должна быть каким-то особым свойством, которое должен проверять копилятор.


Потому что человеку свойственно ошибаться. И когда компилятор бьет по рукам в compile-time, то это (как по мне) много лучше получения ошибок run-time.

·>В любом случае это же просто ментальная пометка для человеков, всего лишь: "не претендует на его изменение".


Не только для человека, это во-первых.

Во-вторых, и это уже очень и очень немало.

·>В java есть virtual call elimination.


В C++ тоже есть девиртуализация вызовов.
Re[44]: Когда это наконец станет defined behavior?
От: σ  
Дата: 12.05.23 10:37
Оценка:
S>>·>Как я понимаю, в плюсах интерфейс — это виртуальный вызов, дорого. Поэтому обычно не используется.
S>>Вряд ли сильно дороже чем в Java
·>В java есть virtual call elimination. В итоге виртуальные методы могут даже инлайниться.
Да, про Java известно, что она, заинлайнив и специализировав всё и вся, может работать быстрее процессора, но почему-то всё равно тормозит (+ жрёт память)
Re[45]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 11:45
Оценка:
Здравствуйте, so5team, Вы писали:

s> S>>И как такое свойство как "константность" проверяется в Java?

s> ·>В смысле имеет ли компилятор модель константности?
s> Да
Просто это частный и не самый интересный случай контракта, чтобы его прямо таки встраивать в компилятор.

s> ·>Просто делается на уровне дизайна, т.е. тоже является частью системы типов.

s> Иными словами "мамой клянусь"
В смысле то, что в get-методе он не даст _случайно_ поменять значение поля? Ну не знаю. Я не помню за последние ~10 лет каких-то ошибок связанных с этим.
Может это где-то и является проблемой, но я с этим не сталкиваюсь.

s> ·>Иными словами, неясно почему именно константность должна быть каким-то особым свойством, которое должен проверять копилятор.

s> Потому что человеку свойственно ошибаться. И когда компилятор бьет по рукам в compile-time, то это (как по мне) много лучше получения ошибок run-time.
Там где это действительно нужно, всегда можно сделать иммутабельный тип.

s> ·>В любом случае это же просто ментальная пометка для человеков, всего лишь: "не претендует на его изменение".

s> Не только для человека, это во-первых.
Только для человека. Компилятор с этим знанием ничего делать не сможет.

s> Во-вторых, и это уже очень и очень немало.

Кому как. А мне мало. Лучше бы он корректность компараторов проверял, вот тут ошибки так ошибки, и последствия вообще непредсказуемые, и хрен найдёшь. Но остаётся только мечтать...

s> ·>В java есть virtual call elimination.

s> В C++ тоже есть девиртуализация вызовов.
Наверное для этого придётся иметь статическую сборку со всеми либами и глобальную оптимизацию.
Ещё надо учесть, слово const было введено много лет назад, когда таких оптимизаций не было, и хоть что-то. Выбор виртуальных интерфейсов тупо не стоял.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[46]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 12:00
Оценка:
Здравствуйте, ·, Вы писали:

·>Просто это частный и не самый интересный случай контракта, чтобы его прямо таки встраивать в компилятор.


Один из самых фундаментальнейших. Правда, в C++ его до ума не довели. А в D слегка переборщили.

Пользователям же Java/C#/Python/Ruby приходится уговаривать себя о том, что это не так уж и нужно.

·>В смысле то, что в get-методе он не даст _случайно_ поменять значение поля?


Как один из вариантов.

·>Ну не знаю.


А мне помогает. Раз-два в год компилятор явно показывает на проблемы в дизайне, когда есть константная ссылка, а объект хочется изменить.

И для этого не нужно городить интерфейсы.

·>Может это где-то и является проблемой, но я с этим не сталкиваюсь.


Аргумент из категории "у меня все работает".

·>Там где это действительно нужно, всегда можно сделать иммутабельный тип.


Так как в Java этот иммутабельный тип выражается кроме как гарантиями от разработчика "мамой клянусь"?

·>Только для человека. Компилятор с этим знанием ничего делать не сможет.


"Не верь глазам своим":
class demo {
  int i_{};

public:
  int value() const { return ++i_; } // Да, тут компилятор ничего сделать не сможет, ага ;)
};


·>Лучше бы он корректность компараторов проверял


Да и вообще нет кнопки "сделать зашибись!", так что "на помоечку", адназначна!

В Java компараторы компилятором проверяются?

·>Ещё надо учесть, слово const было введено много лет назад, когда таких оптимизаций не было, и хоть что-то. Выбор виртуальных интерфейсов тупо не стоял.


Выбор виртуальных интерфейсов встал перед Java-разработчиками из-за того, что Гослинг и Ко не смогли взять из C++ действительно лучшее, что в нем тогда было: ни константности, ни обобщенного программирования. Что поделать, знания C++ там застряли где-то на уровне 1989-го года, когда предтеча Java в проекте Oak задышала.
Re[47]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 12:55
Оценка: :)
Здравствуйте, so5team, Вы писали:

s> Один из самых фундаментальнейших. Правда, в C++ его до ума не довели. А в D слегка переборщили.

Я тоже так думал, когда на плюсах много писал. И когда начал изучать java — очень не хватало и считал очень важным. Потом, с опытом, прошло.

s> ·>В смысле то, что в get-методе он не даст _случайно_ поменять значение поля?

s> Как один из вариантов.
Ну не знаю, может на этапе освоения программирования это и является проблемой, но и только и всего.

s> ·>Ну не знаю.

s> А мне помогает. Раз-два в год компилятор явно показывает на проблемы в дизайне, когда есть константная ссылка, а объект хочется изменить.
Так и с интерфейсами. Хочется дёрнуть этот метод, а он у класса, а в интерфейсе нет.

s> И для этого не нужно городить интерфейсы.

Нет никакого "городить". В плюсах приходится писать два варианта методов const|non-const, в java нужно только сигнатуру объявлять в интерфейсе. Кода даже меньше по итогу. А с современным IDE это всё элементарно рефакторится туда-сюда.

s> ·>Там где это действительно нужно, всегда можно сделать иммутабельный тип.

s> Так как в Java этот иммутабельный тип выражается кроме как гарантиями от разработчика "мамой клянусь"?
Что его значение никак не поменять. Нет способа "снять иммутабельность". Вроде можно через рефлексию (которую можно запретить), но без гарантий. Ещё теоретически можно через нативный вызов попортить участок памяти... но это уже не про java.

s> ·>Только для человека. Компилятор с этим знанием ничего делать не сможет.

s> int value() const { return ++i_; } // Да, тут компилятор ничего сделать не сможет, ага
А человек может.

s> В Java компараторы компилятором проверяются?

Нет, конечно. Надо AI встроить

s> ·>Ещё надо учесть, слово const было введено много лет назад, когда таких оптимизаций не было, и хоть что-то. Выбор виртуальных интерфейсов тупо не стоял.

s> Выбор виртуальных интерфейсов встал перед Java-разработчиками из-за того, что Гослинг и Ко не смогли взять из C++ действительно лучшее, что в нем тогда было: ни константности, ни обобщенного программирования. Что поделать, знания C++ там застряли где-то на уровне 1989-го года, когда предтеча Java в проекте Oak задышала.
Виртуальность по дефолту — было осознанным стратегическим решением. И, вроде неплохо вышло, получился вполне популярный яп.
Много чего упрощает, написание тестов, например.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[45]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 13:09
Оценка:
Здравствуйте, so5team, Вы писали:

S>Да, оказывается вы вещаете не о C++, а о каких-то своих фантазиях.

Я к тому что надо что бы компилятор преобразовывал код на основе не верных предположений, используя наркоманские допущения из стандарта. А была возможность явно указывать все допущения, ограничения и предположения которые компилятор может смело использовать без необходимости что-то выдумывать. Все допущения по умолчанию как раз и являются источниками всех UB.

S>Этот ваш гипотетический язык пока только в ваших мечтах существует или уже есть какой-то работающий прототип?

Нет это можно делать на обычном C, но только с дополнительными телодвижениями.
Re[48]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 13:18
Оценка:
Здравствуйте, ·, Вы писали:

s>> Один из самых фундаментальнейших. Правда, в C++ его до ума не довели. А в D слегка переборщили.

·>Я тоже так думал, когда на плюсах много писал. И когда начал изучать java — очень не хватало и считал очень важным. Потом, с опытом, прошло.

Или стокгольмский синдром

Я с момента появления Java несколько раз был вынужден ее использовать, и каждый раз натыкался на то, что в ней не хватает хотя бы константности из C++

·>Так и с интерфейсами. Хочется дёрнуть этот метод, а он у класса, а в интерфейсе нет.

·>Нет никакого "городить". В плюсах приходится писать два варианта методов const|non-const, в java нужно только сигнатуру объявлять в интерфейсе. Кода даже меньше по итогу. А с современным IDE это всё элементарно рефакторится туда-сюда.

А интерфейсы откуда берутся? Ладно бы Java позволяла отдельно определить тип, отдельно интерфейсы, да еще чтобы можно было автоматически объект привести к нужному интерфейсу (что-то вроде того, что в Go сделано). А то нужно сперва сделать интерфейс, потом в типе его имплементировать.

IDE, может быть, помогают писать ручками меньше, но всю эту кухню все равно в голове держать нужно.

И да, в C++ сейчас больше чем два варианта const|non-const: &, const &, && и, для ценителей, const &&
Правда, в C++23 вроде как это дело поправят, но как зачастую бывает в C++, через жопу.

s>> ·>Там где это действительно нужно, всегда можно сделать иммутабельный тип.

s>> Так как в Java этот иммутабельный тип выражается кроме как гарантиями от разработчика "мамой клянусь"?
·>Что его значение никак не поменять. Нет способа "снять иммутабельность"

Т.е. если программист не напишет setter, то тип считается иммутабельным?

s>> ·>Только для человека. Компилятор с этим знанием ничего делать не сможет.

s>> int value() const { return ++i_; } // Да, тут компилятор ничего сделать не сможет, ага
·>А человек может.

Тогда он ССЗБ. Компилятор его честно предупреждал. А вот когда даже таких предупреждений нет, то печально. Приходится городить интерфейсы и радоваться тому, что IDE это упрощает.

s>> В Java компараторы компилятором проверяются?

·>Нет, конечно. Надо AI встроить

О том и речь

·>Виртуальность по дефолту — было осознанным стратегическим решением. И, вроде неплохо вышло, получился вполне популярный яп.


Он не из-за этого стал популярным. Но речь о другом: авторы Java могли бы сделать его еще лучше сразу, если бы умели в C++ (а у меня есть сомнения, что умели). Однако, если бы они сразу взяли из C++ константаность и обобщенное программирование, то не факт, что язык настолько быстро и высоко взлетел бы.

Впрочем, это уже совсем другая история.
Re[46]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 13:19
Оценка:
Здравствуйте, kov_serg, Вы писали:

S>>Да, оказывается вы вещаете не о C++, а о каких-то своих фантазиях.

_>Я к тому что надо что бы компилятор

Да-да-да, лучше быть богатым и здоровым, чем...

S>>Этот ваш гипотетический язык пока только в ваших мечтах существует или уже есть какой-то работающий прототип?

_>Нет это можно делать на обычном C, но только с дополнительными телодвижениями.

Посмотреть на это можно где-то?
Re[49]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 13:55
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Я тоже так думал, когда на плюсах много писал. И когда начал изучать java — очень не хватало и считал очень важным. Потом, с опытом, прошло.

s> Или стокгольмский синдром
Ага, но я не страдаю, я наслаждаюсь.

s> Я с момента появления Java несколько раз был вынужден ее использовать, и каждый раз натыкался на то, что в ней не хватает хотя бы константности из C++

Сила привычки и только.

s> А интерфейсы откуда берутся? Ладно бы Java позволяла отдельно определить тип, отдельно интерфейсы, да еще чтобы можно было автоматически объект привести к нужному интерфейсу (что-то вроде того, что в Go сделано). А то нужно сперва сделать интерфейс, потом в типе его имплементировать.

Просто другой mind-set. По кол-ву усилий — нисколько.

s> IDE, может быть, помогают писать ручками меньше, но всю эту кухню все равно в голове держать нужно.

Как правило пишется тип, а потом, если надо, рефакторингом выделяется интерфейс.
Не знаю что именно ты считаешь нужно держать в голове.

s> И да, в C++ сейчас больше чем два варианта const|non-const: &, const &, && и, для ценителей, const &&

s> Правда, в C++23 вроде как это дело поправят, но как зачастую бывает в C++, через жопу.
Мде... Больше — лучше!

s> ·>Что его значение никак не поменять. Нет способа "снять иммутабельность"

s> Т.е. если программист не напишет setter, то тип считается иммутабельным?
Иммутабельный тип имеет final-поля, которые нельзя изменить, нет никакого механизма снять final. А так же тип обычно тоже final (т.е. нельзя унаследоваться и переопределить поведение).

Можно делать некоторые исключения. Например, для lazy initialisation, когда в иммутабельном типе может быть non-final поле.

Константность это немного о другом. Это когда у тебя есть некий объект и в одном месте ты можешь его менять его состояние, а в другом — не можешь.
Если не зацикливаться на конкретно "менять", а обобщить до "совершать некие операции", то интерфейсы — оно и есть.

s> ·>А человек может.

s> Тогда он ССЗБ. Компилятор его честно предупреждал. А вот когда даже таких предупреждений нет, то печально. Приходится городить интерфейсы и радоваться тому, что IDE это упрощает.
Ты так говоришь, как будто это что-то плохое
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[50]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 14:23
Оценка:
Здравствуйте, ·, Вы писали:

s>> Или стокгольмский синдром

·>Ага, но я не страдаю, я наслаждаюсь.

А это одно из его проявлений

s>> А интерфейсы откуда берутся? Ладно бы Java позволяла отдельно определить тип, отдельно интерфейсы, да еще чтобы можно было автоматически объект привести к нужному интерфейсу (что-то вроде того, что в Go сделано). А то нужно сперва сделать интерфейс, потом в типе его имплементировать.

·>Просто другой mind-set.

Ну да, простой константности нет, приходится выкручиваться по другому.

·>Не знаю что именно ты считаешь нужно держать в голове.


Представления о типах еще до того, как они были реализованы. И взаимоотношения между типами когда они уже были реализованы.

·>Иммутабельный тип имеет final-поля, которые нельзя изменить, нет никакого механизма снять final. А так же тип обычно тоже final (т.е. нельзя унаследоваться и переопределить поведение).


Грубо говоря:
class Data {
  public void change() {...}
  ...
}

class ImmutableData final {
  public final Data data = new Data(...);
  ...
}

...
final ImmutableData immutableData = new ImmutableData(...);

Если речь про это, то разве в Java нельзя сделать вызов immutableData.data.change()?

·>Константность это немного о другом. Это когда у тебя есть некий объект и в одном месте ты можешь его менять его состояние, а в другом — не можешь.


Это только часть проблемы.

·>Если не зацикливаться на конкретно "менять", а обобщить до "совершать некие операции", то интерфейсы — оно и есть.


Опять приходим к тому, что в Java от компилятора в этом нет никакой помощи. Тогда как в более продвинутых языках (и речь не только про C++) иммутабельность/константность -- это одна из мега-фич, как и контроль за этим со стороны компилятора.

s>>Приходится городить интерфейсы и радоваться тому, что IDE это упрощает.

·>Ты так говоришь, как будто это что-то плохое

Да, это ущербность. К которой можно и привыкнуть, и научиться ее преодолевать с помощью IDE. Но ущербностью она быть не перестает.
Re[38]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 12.05.23 14:34
Оценка:
Здравствуйте, kov_serg, Вы писали:
_>Какая фантастика https://tour.dlang.org/tour/en/gems/contract-programming

В C тоже есть assert'ы
И каждый день — без права на ошибку...
Re[47]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 12.05.23 15:49
Оценка:
Здравствуйте, so5team, Вы писали:

S>Да-да-да, лучше быть богатым и здоровым, чем...

S>Посмотреть на это можно где-то?

Извини, что не поддерживаю. У меня уже ни сил, ни желания участвовать в этой дискуссии.
--
Справедливость выше закона. А человечность выше справедливости.
Re[51]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 16:05
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Ага, но я не страдаю, я наслаждаюсь.

s> А это одно из его проявлений
Я могу бросить!! В любой момент!!!

s> ·>Просто другой mind-set.

s> Ну да, простой константности нет, приходится выкручиваться по другому.
Просто константность — невеликая проблема.

s> ·>Не знаю что именно ты считаешь нужно держать в голове.

s> Представления о типах еще до того, как они были реализованы. И взаимоотношения между типами когда они уже были реализованы.
Это mind-set какого-то нотепада. Есть же рефакторинги. "Выделить интерфейс", "переместить метод в потомка|предка" и т.п.
Не надо продумывать всё досконально и не иметь права на ошибку. Если что-то не так, можно быстро исправить.

s> Если речь про это, то разве в Java нельзя сделать вызов immutableData.data.change()?

Можно. Но
Во-первых, иммутабельный тип по правилам собирается из иммутабельных. Либо держит мутабельные вещи у себя внутри и наружу не отдаёт.
Во-вторых, иногда нужно. Например этот самый change() может быть сборщиком статистики или логов, такое надо по дизайну. Перезаворачивать всё в mutable — тоже так себе.
В-третьих, ещё ты забыл вариант, когда data заходит внутрь ImmutableData через конструктор. От такого и const не поможет.
В-четвёртых, иммутабельность и константность всё-таки разные вещи.

s> ·>Константность это немного о другом. Это когда у тебя есть некий объект и в одном месте ты можешь его менять его состояние, а в другом — не можешь.

s> Это только часть проблемы.
А другая часть?

s> ·>Если не зацикливаться на конкретно "менять", а обобщить до "совершать некие операции", то интерфейсы — оно и есть.

s> Опять приходим к тому, что в Java от компилятора в этом нет никакой помощи. Тогда как в более продвинутых языках (и речь не только про C++) иммутабельность/константность -- это одна из мега-фич, как и контроль за этим со стороны компилятора.
Если её можно снимать, то смысл как-то теряется. А без её снятия не сделаешь некоторые полезные вещи.

s> ·>Ты так говоришь, как будто это что-то плохое

s> Да, это ущербность. К которой можно и привыкнуть, и научиться ее преодолевать с помощью IDE. Но ущербностью она быть не перестает.
Просто это такая мелочь, что вообще не ощущается как проблема. Нечего преодолевать собственно.
А IDE всё равно будет. Т.к. помощь IDE не только в этом, а ещё в очень многом.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[39]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 16:16
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В C тоже есть assert'ы


Почти assert-ы но только помимо проверок они могли-бы компилятору помогать с оптимизацией. assert сам по себе просто проверка некоторого условия.
Вот смотрите вы хотите передать объект в функцию и хотите что бы выполнялось какое-то условие, но и функция может требовать соблюдение определённых условий для своей работы.
И если они не совместимы можно предупреждать или делать переходники.
Assert-ы не позволяют эти данные использовать, только проверить на конкретных данных. Эта невозможность порождает всякие методики тестирования типа fuzzing
Re[52]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 16:40
Оценка:
Здравствуйте, ·, Вы писали:

·>Я могу бросить!! В любой момент!!!


Конечно, я сам так делал несколько раз

·>Просто константность — невеликая проблема.


Наличие константности -- это вообще благо. А вот отсутствие...

К сожалению, в C++ константность недостаточно строгая

·>Не надо продумывать всё досконально и не иметь права на ошибку. Если что-то не так, можно быстро исправить.


"фигак-фигак-и-в-продакшен" mind-set detected

s>> Если речь про это, то разве в Java нельзя сделать вызов immutableData.data.change()?

·>Можно.

О том и речь, что неизменяемость данных в Java -- это очень непростой вопрос. И Java точно не тот язык, который следовало бы приводить в пример.

·>В-четвёртых, иммутабельность и константность всё-таки разные вещи.


В C++ речь может идти только о константности, которая в большом количестве случаев тождественна иммутабельности, но есть нюансы...

s>> ·>Константность это немного о другом. Это когда у тебя есть некий объект и в одном месте ты можешь его менять его состояние, а в другом — не можешь.

s>> Это только часть проблемы.
·>А другая часть?

Что константность может быть как раз иммутабельностью. Грубо говоря:
const std::string hello{ "Hello, World" };

и у нас реально константный объект.

В C++ не хватает возможности при передаче по константной ссылке/указателю сказать потребителю, что он (потребитель) имеет дело именно с иммутабельным значением. Из-за этого у потребителя есть большой вопрос: а насколько он может доверять полученной ссылке (указателю). Вот тут-то основные проблемы и появляются.

·>Если её можно снимать, то смысл как-то теряется. А без её снятия не сделаешь некоторые полезные вещи.


Из моего опыта: применение const_cast _всегда_ указывает на наличие проблем. Это костыль, появление которого в коде означает, что где-то что-то пора поменять.

·>А IDE всё равно будет. Т.к. помощь IDE не только в этом, а ещё в очень многом.


Охотно верю. Но когда без IDE языком становится пользоваться невозможно (как в случае с Java), то с этим языком что-то сильно не так.
Re[46]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 12.05.23 17:02
Оценка:
Здравствуйте, ·, Вы писали:

·>Там где это действительно нужно, всегда можно сделать иммутабельный тип.


Как жаба следит чтоб ты не менял ключи хешмап?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[49]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 12.05.23 17:06
Оценка: :)
Здравствуйте, so5team, Вы писали:


S>И да, в C++ сейчас больше чем два варианта const|non-const: &, const &, && и, для ценителей, const &&

S>Правда, в C++23 вроде как это дело поправят, но как зачастую бывает в C++, через жопу.

Там шо, введут
&&&

?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[40]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 12.05.23 17:16
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>В C тоже есть assert'ы

_>Почти assert-ы но только помимо проверок они могли-бы компилятору помогать с оптимизацией. assert сам по себе просто проверка некоторого условия.
_>Вот смотрите вы хотите передать объект в функцию и хотите что бы выполнялось какое-то условие, но и функция может требовать соблюдение определённых условий для своей работы.
_>И если они не совместимы можно предупреждать или делать переходники.
_>Assert-ы не позволяют эти данные использовать, только проверить на конкретных данных. Эта невозможность порождает всякие методики тестирования типа fuzzing

Не понятно.
Хотите что-то проверить компилятором, то есть static_assert.
Хотите переходники, то просто пишите if (условие) goto
Какая разница, напишите вы эти условия в секциях in/out или просто в коде?
Всё равно: приходящие из внешнего мира данные вы никак не проверите, кроме как в run-тайме.
И каждый день — без права на ошибку...
Re[44]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 12.05.23 17:37
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Разница огромна. Вместо дополнительного типа у нас требования (ограничения) которые должна соблюдать функция. Они могут описывать разные виды ограничений.

_>Например:
_>
void do_something(int o[3]) where o[1] is immutable; -- запрещено менять o[1]


И что будет если:
void do_something(int o[3]) where o[1] is immutable // -- запрещено менять o[1]
{
   o[rand() % 3] = 1;
}

?
И каждый день — без права на ошибку...
Re[50]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 17:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> Там шо, введут

TB> &&&
Не. &&++ же.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[47]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 17:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> ·>Там где это действительно нужно, всегда можно сделать иммутабельный тип.

TB> Как жаба следит чтоб ты не менял ключи хешмап?
Не следит. Это в принципе невозможно по крайней мере в подавляющем числе ЯП. Что если у тебя ключ get_current_time()?
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[48]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 12.05.23 17:46
Оценка: +2
Здравствуйте, ·, Вы писали:

·>Не следит. Это в принципе невозможно по крайней мере в подавляющем числе ЯП. Что если у тебя ключ get_current_time()?


В С++ есть const. Этого достаточно. Написать const_cast можно, но случайно — нет.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[53]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 17:56
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Я могу бросить!! В любой момент!!!

s> Конечно, я сам так делал несколько раз
А на людей я и не бросаюсь.

s> ·>Просто константность — невеликая проблема.

s> Наличие константности -- это вообще благо. А вот отсутствие...
Хаскель же уж если так хочется. А то ведь смотря какая константность:

s> К сожалению, в C++ константность недостаточно строгая

Именно.

s> ·>Не надо продумывать всё досконально и не иметь права на ошибку. Если что-то не так, можно быстро исправить.

s> "фигак-фигак-и-в-продакшен" mind-set detected
Не совсем. YAGNI же.

s> ·>Можно.

s> О том и речь, что неизменяемость данных в Java -- это очень непростой вопрос. И Java точно не тот язык, который следовало бы приводить в пример.
Это не в java, а в программировании вообще.
Впрочем, если так хочется неизменяемости, можно взять Скалу на той же платформе. Но, честно говоря, меня оно не впечатлило. Да, данные иммутабельы, но просто меняется стиль работы с ними. Выстраиваются цепочки созданий копий данных с изменениями и в итоге изменения-то есть, и все проблемы с ними связанные, но писать код сложнее стало.
Было
var data = ...
modifyX(data);
modifyY(data);

стало
var data = ...
data = modifyX(data);
data = modifyY(data);

а проблемы те же.

s> В C++ речь может идти только о константности, которая в большом количестве случаев тождественна иммутабельности, но есть нюансы...

Нюансы, да.

s> ·>А другая часть?


s> Что константность может быть как раз иммутабельностью. Грубо говоря:

s>
s> const std::string hello{ "Hello, World" };
s>

s> и у нас реально константный объект.
Он константный лишь потому, что так говорит Стандарт про std::string. А если это какой-то левый тип, там внезапно зависимость от статик переменной и приплыли.
А так в java то же самое final String hello = "Hello, World" реально иммутабельный объект в константной переменной.

s> В C++ не хватает возможности при передаче по константной ссылке/указателю сказать потребителю, что он (потребитель) имеет дело именно с иммутабельным значением. Из-за этого у потребителя есть большой вопрос: а насколько он может доверять полученной ссылке (указателю). Вот тут-то основные проблемы и появляются.

В java делают defensive copy, как правило.

s> ·>Если её можно снимать, то смысл как-то теряется. А без её снятия не сделаешь некоторые полезные вещи.

s> Из моего опыта: применение const_cast _всегда_ указывает на наличие проблем. Это костыль, появление которого в коде означает, что где-то что-то пора поменять.
Вот в скажем в том же String — есть поле hashCode, которое неконстантное. При первом вызове метода хеш-код считается и записывается в эту переменную. Последующие вызовы используют предыдущее значение. Так что формально внутреннее состояние объекта неконстантно, но внешне объект всё ещё иммутабельный.

s> ·>А IDE всё равно будет. Т.к. помощь IDE не только в этом, а ещё в очень многом.

s> Охотно верю. Но когда без IDE языком становится пользоваться невозможно (как в случае с Java), то с этим языком что-то сильно не так.
Или наоборот — сильно так. ЯП умудряется быть не только простым для человека, но и поддаётся автоматической обработке.
Иначе тебе приходится очень аккуратно думать как назвать каждую переменную и функцию и т.п. Без рефакторингов это будет дорогой ошибкой, если придётся потом что-то поменять.
Может быть это важно для написания каких-то общеиспользуемых библиотек, но в обычных аппликухах это не так.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[50]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 12.05.23 18:01
Оценка: 19 (3)
Здравствуйте, T4r4sB, Вы писали:

S>>И да, в C++ сейчас больше чем два варианта const|non-const: &, const &, && и, для ценителей, const &&

S>>Правда, в C++23 вроде как это дело поправят, но как зачастую бывает в C++, через жопу.

TB>Там шо, введут

TB>
TB>&&&
TB>


Хуже

https://habr.com/ru/articles/722668/

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html

template <typename T>
class optional {
  // ...
  template <typename Self>
  constexpr auto operator->(this Self&& self) {
    return addressof(self.m_value);
  }
  // ...
};
Re[49]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 18:07
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> ·>Не следит. Это в принципе невозможно по крайней мере в подавляющем числе ЯП. Что если у тебя ключ get_current_time()?

TB> В С++ есть const. Этого достаточно. Написать const_cast можно, но случайно — нет.
Не понял, ты же в мапу ключ кладёшь снаружи. Или мапа копию делает?
Скажем, ключом в мапе может быть массив из миллиона элементов... Дальше продолжать?
Не говоря уж о том, что может быть зависимость от статической переменной.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[50]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 12.05.23 19:34
Оценка:
Здравствуйте, ·, Вы писали:

·>Не понял, ты же в мапу ключ кладёшь снаружи. Или мапа копию делает?


Копию, конечно.

·>Скажем, ключом в мапе может быть массив из миллиона элементов... Дальше продолжать?


Мув-копию.
Когда жабисты рассказывают о крестах, иногда такой кринж

·>Не говоря уж о том, что может быть зависимость от статической переменной.


Ну ещё можно хреново написать хеш-функцию, (чтоб она зависела от таймера например), тоже мапа поломается. Только хеш-функцию пишется один раз, а вот итерация по мапе делается регулярно и там проследить за кривыми руками кодера сложнее.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[45]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 12.05.23 19:49
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>И что будет если:

BFE>
BFE>void do_something(int o[3]) where o[1] is immutable // -- запрещено менять o[1]
BFE>{
BFE>   o[rand() % 3] = 1;
BFE>}
BFE>

BFE>?
Очевидно же будет нарушение контракта в 1/3 случаев. Поэтому надо писать так
void do_something(int o[3]) where o[1] is immutable // -- запрещено менять o[1]
{
   int idx=rand() % 3;
   if (idx!=1) o[idx] = 1;
}

Более того раз это очевидно это может делать компилятор.
Re[51]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 12.05.23 20:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> ·>Не понял, ты же в мапу ключ кладёшь снаружи. Или мапа копию делает?

TB> Копию, конечно.
А если указатель?

TB> ·>Скажем, ключом в мапе может быть массив из миллиона элементов... Дальше продолжать?

TB> Мув-копию.
А если массив является ключом в двух разных мапах?

TB> Когда жабисты рассказывают о крестах, иногда такой кринж

Ты ещё не слушал плюсовиков, которые рассуждают о жабе.

TB> ·>Не говоря уж о том, что может быть зависимость от статической переменной.

TB> Ну ещё можно хреново написать хеш-функцию, (чтоб она зависела от таймера например), тоже мапа поломается. Только хеш-функцию пишется один раз,
К сожалению нет. Класс ключа может меняться, добавляться новые поля, например.

TB> а вот итерация по мапе делается регулярно и там проследить за кривыми руками кодера сложнее.

Короче, может и есть какие-то средства, работающие в каких-то сценариях, никакой гарантии нет.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[54]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 13.05.23 05:12
Оценка:
Здравствуйте, ·, Вы писали:

s>> ·>Просто константность — невеликая проблема.

s>> Наличие константности -- это вообще благо. А вот отсутствие...
·>Хаскель же уж если так хочется.

Haskell или OCaml хорошие примеры, но там GC, это другая область. Меня радует, что в Rust-е сделали константность. Причем предположу, что там за счет borrow checker-а похожая на C++ модель константности работает лучше, чем в C++ (но утверждать не могу, дальше hello-world-ов у меня с Rust-ом не зашло).

s>> ·>Не надо продумывать всё досконально и не иметь права на ошибку. Если что-то не так, можно быстро исправить.

s>> "фигак-фигак-и-в-продакшен" mind-set detected
·>Не совсем. YAGNI же.

C++ более требовательный язык и задачи на нем простотой не отличаются, так что здесь "не совсем" и "yagni" имеют другой привкус.

·>Это не в java, а в программировании вообще.


"Отучаемся говорить за всех" (с)

s>> Что константность может быть как раз иммутабельностью. Грубо говоря:

s>>
s>> const std::string hello{ "Hello, World" };
s>>

s>> и у нас реально константный объект.
·>Он константный лишь потому, что так говорит Стандарт про std::string.

Замените std::string на любой пользовательский тип и вы обнаружите, что для const объекта компилятор разрешает вызывать только const-методы. А в const-методах нельзя менять поля объекта.

И это изкаропки и бесплатно.

·>А если это какой-то левый тип, там внезапно зависимость от статик переменной и приплыли.


Как приплыли, куда приплыли, ничего не понятно.

·>А так в java то же самое final String hello = "Hello, World" реально иммутабельный объект в константной переменной.


Так это у вас безусловный рефлекс на то, что в Java String -- это иммутабельная строка, вот вам и кажется, что вы приводите аналогичный пример. Замените std::string на std::vector из std::queue и ничего не поменяется. В отличии от Java.

·>В java делают defensive copy, как правило.


Так память же не ресурс!

·>Вот в скажем в том же String — есть поле hashCode, которое неконстантное. При первом вызове метода хеш-код считается и записывается в эту переменную. Последующие вызовы используют предыдущее значение. Так что формально внутреннее состояние объекта неконстантно, но внешне объект всё ещё иммутабельный.


В C++ для этих целей есть mutable, который устраняет надобность во многих const_cast. А вот когда в коде появляется const_cast, то это уже признак наличия какого-то костыля.

·>Или наоборот — сильно так.


Не так. Есть языки посложнее Java (или C#), которые десятилетиями живут без IDE уровня IDEA или VisualStudio и это никому не мешает.

·>Иначе тебе приходится очень аккуратно думать как назвать каждую переменную и функцию и т.п.


А вы не думаете?
Хотя да, "фигак-фигак-и-в-продакшен" mind-set и все дела

·>Без рефакторингов это будет дорогой ошибкой, если придётся потом что-то поменять.


Или не будет.

·>Может быть это важно для написания каких-то общеиспользуемых библиотек, но в обычных аппликухах это не так.


Мне не доводилось видеть разработки на C++ "обычных аппликух" уже лет 20, наверное.
Re[55]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 10:18
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Хаскель же уж если так хочется.

s> Haskell или OCaml хорошие примеры, но там GC, это другая область. Меня радует, что в Rust-е сделали константность. Причем предположу, что там за счет borrow checker-а похожая на C++ модель константности работает лучше, чем в C++ (но утверждать не могу, дальше hello-world-ов у меня с Rust-ом не зашло).
Да, borrow checker нужен для нормальной реализации константности. Иначе полумеры.

s> ·>Не совсем. YAGNI же.

s> C++ более требовательный язык и задачи на нем простотой не отличаются, так что здесь "не совсем" и "yagni" имеют другой привкус.
Я имею в виду не бизнес-задачи, а задачи манипуляции кодом. Почему, например, перенос метода между классами _должно_ быть сложной задачей?

s> ·>Это не в java, а в программировании вообще.

s> "Отучаемся говорить за всех" (с)
Ну вот видишь, нетривиальный borrow checker ещё как-то может это решить. А не этот ваш const.

s>>> и у нас реально константный объект.

s> ·>Он константный лишь потому, что так говорит Стандарт про std::string.
s> Замените std::string на любой пользовательский тип и вы обнаружите, что для const объекта компилятор разрешает вызывать только const-методы. А в const-методах нельзя менять поля объекта.
Так это просто неявный интерфейс, вот и всё.
std::string oops{ "Hello, World" };
const std::string &hello = oops;

и уже бардак. Как бы константный объект, но уже нереально, оксюморон "изменяемая константа" получается внезапно.

s> И это изкаропки и бесплатно.

Как и интерфейсы в java.

s> ·>А если это какой-то левый тип, там внезапно зависимость от статик переменной и приплыли.

s> Как приплыли, куда приплыли, ничего не понятно.
Состояние объекта меняется.
constObj.getX();
...
constObj.getX();

может иметь разный результат.

А иммутабельность гарантирует, что результат будет одинаковый, не смотря ни на что.

s> ·>А так в java то же самое final String hello = "Hello, World" реально иммутабельный объект в константной переменной.

s> Так это у вас безусловный рефлекс на то, что в Java String -- это иммутабельная строка, вот вам и кажется, что вы приводите аналогичный пример. Замените std::string на std::vector из std::queue и ничего не поменяется. В отличии от Java.
List.of(1, 2, 3) тоже иммутабельный. А зачем иметь queue константную, чтобы что? Чтобы, например, дать возможность перебрать, но запретить добавлять. Ну так она имплементирует интерфейс Iterable, внезапно. И Iterable likeAConstQueue = queue даёт тебе что ты хочешь (с небольшими оговорками).

s> ·>В java делают defensive copy, как правило.

s> Так память же не ресурс!
А в плюсах как иммутабельность делать? Других вариантов тупо нет. ownership можно передавать, но это частный случай.

Иммутабельность — полезная вещь. Константность — очень спорная полезность.

s> В C++ для этих целей есть mutable, который устраняет надобность во многих const_cast. А вот когда в коде появляется const_cast, то это уже признак наличия какого-то костыля.

Но уже этот mutable сводит на нет идею константности.
Можешь считать, что в java просто умолчание другое — все поля mutable по дефолту, кроме обозначенных final.

s> ·>Или наоборот — сильно так.

s> Не так. Есть языки посложнее Java (или C#), которые десятилетиями живут без IDE уровня IDEA или VisualStudio и это никому не мешает.
Ах да, конечно, бедность — не порок.

s> ·>Иначе тебе приходится очень аккуратно думать как назвать каждую переменную и функцию и т.п.

s> А вы не думаете?
s> Хотя да, "фигак-фигак-и-в-продакшен" mind-set и все дела
Решение задачи важнее, чем названия методов. Методы можно потом переименовать, когда тесты проходят. А ещё требования любят меняться, потом.

s> ·>Без рефакторингов это будет дорогой ошибкой, если придётся потом что-то поменять.

s> Или не будет.
"Работает — не трожь" mind-set? Нет, я люблю чтоб и красиво тоже было.

s> ·>Может быть это важно для написания каких-то общеиспользуемых библиотек, но в обычных аппликухах это не так.

s> Мне не доводилось видеть разработки на C++ "обычных аппликух" уже лет 20, наверное.
"Обычные", в смысле не API. Что ты под этим подразумеваешь — не знаю.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[56]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 13.05.23 11:07
Оценка:
Здравствуйте, ·, Вы писали:

s>> ·>Хаскель же уж если так хочется.

s>> Haskell или OCaml хорошие примеры, но там GC, это другая область. Меня радует, что в Rust-е сделали константность. Причем предположу, что там за счет borrow checker-а похожая на C++ модель константности работает лучше, чем в C++ (но утверждать не могу, дальше hello-world-ов у меня с Rust-ом не зашло).
·>Да, borrow checker нужен для нормальной реализации константности. Иначе полумеры.

В D сделали иммутабельность и без borrow checker-а.

·>Я имею в виду не бизнес-задачи, а задачи манипуляции кодом. Почему, например, перенос метода между классами _должно_ быть сложной задачей?


А это сложная задача?

s>> ·>Это не в java, а в программировании вообще.

s>> "Отучаемся говорить за всех" (с)
·>Ну вот видишь, нетривиальный borrow checker ещё как-то может это решить. А не этот ваш const.

Так у нас в C++ хотя бы const есть, а в Java и этого нет.

·>Так это просто неявный интерфейс, вот и всё.


Может вам матчасть подучить?

·>
·>std::string oops{ "Hello, World" };
·>const std::string &hello = oops;
·>

·>и уже бардак.

Таки да, марш учить матчасть.

·>Как бы константный объект


Как бы константным объектом здесь и не пахнет. От слова совсем.

s>> И это изкаропки и бесплатно.

·>Как и интерфейсы в java.

Так уже выяснили, что интерфейсы Java к константности отношения не имеют. Просто привыкли жрать что дали и научились получать удовольствие.

·>Состояние объекта меняется.

·>
·>constObj.getX();
·>...
·>constObj.getX();
·>

·>может иметь разный результат.

А кто сказал, что getX имеет отношение к состоянию объекта? Стиль наименования как в Java?

·>А иммутабельность гарантирует, что результат будет одинаковый, не смотря ни на что.


Ну и в C++ у нас есть помощь со стороны компилятора в ее обеспечении, в отличии от.

·>List.of(1, 2, 3) тоже иммутабельный.


А у вас, походу, фантазия вообще отсутствует.

·>А зачем иметь queue константную, чтобы что?


Чтобы показать, что в C++ константой можно сделать даже то, что на такую роль и не предполагалось.

·>А в плюсах как иммутабельность делать?


Поверить тому, что переданное по константной ссылке и есть константа.

·>Иммутабельность — полезная вещь. Константность — очень спорная полезность.


Вам бы еще понять, что в нормальных языках константность на уровне языка сильно помогает в достижении иммутабельности. Но с этим пониманием явно проблемы, mind-set полагаю, плюс отсутствие воображения.

·>Можешь считать, что в java просто умолчание другое — все поля mutable по дефолту, кроме обозначенных final.


Вы бы уяснили себе, что final в Java запрещает присвоить новое значение ссылке. И не более того. А то мне, как C++нику, как-то совестно об этом вам напоминать.

·>Ах да, конечно, бедность — не порок.


Нет, просто языки делались людьми для людей, а не для заработка на индусах разных национальностей.

s>> ·>Без рефакторингов это будет дорогой ошибкой, если придётся потом что-то поменять.

s>> Или не будет.
·>"Работает — не трожь" mind-set?

Нет, вы не поняли. Не будет дорогой ошибкой если придется потом что-то поменять.

·>"Обычные", в смысле не API. Что ты под этим подразумеваешь — не знаю.


Обычные -- это такие, в которых нет суровых требований к сложности/ресурсоемкости/производительности. Вне зависимости от того, бэкэнд это, GUI, CLI или еще что-то.
Re[57]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 13.05.23 11:48
Оценка:
Здравствуйте, so5team, Вы писали:

S>В D сделали иммутабельность и без borrow checker-а.


То есть компилятор D точно знает, что если в функцию передали const*, то пока выполняется функция, объект невозможно изменить никакими внешними способами? В С++ это не так, в Русте это так за счёт борзочекара.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[52]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 13.05.23 11:50
Оценка:
Здравствуйте, ·, Вы писали:

·>А если указатель?


Можно использовать указатель как ключ, почему б и нет.

·>А если массив является ключом в двух разных мапах?


Тогда копировать, да.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[53]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 12:03
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>·>А если массив является ключом в двух разных мапах?


TB>Тогда копировать, да.


Тут могут быть варианты — в качестве ключей можно использовать указатели и std::reference_wrapper-ы с кастомными хэшерами/компараторами.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 13.05.2023 12:04 rg45 . Предыдущая версия .
Re[58]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 13.05.23 12:04
Оценка:
Здравствуйте, T4r4sB, Вы писали:

S>>В D сделали иммутабельность и без borrow checker-а.


TB>То есть компилятор D точно знает, что если в функцию передали const*, то пока выполняется функция, объект невозможно изменить никакими внешними способами?


В D есть понятие immutable: https://dlang.org/spec/const3.html
Насколько я помню, то const ссылку на immutable можно передать, в этом случае компилятор знает, что по const ссылке значение менять не будут.
Использует ли это компилятор для оптимизаций -- хз, я давным-давно перестал следить за D и его возможностями. Когда-то давно компилятор D базировался на кодовой базе от Digital Mars C++ и вряд ли оптимизатор там был такой же продвинутый, как у GCC/MSVC/Clang конца 00-х. Перешел ли сейчас референсный dmd на какой-то современный продвинутый бэкэнд не в курсе.

Насколько помню, если в функцию/метод передается immutable ссылка, то внутри функции/метода можно быть уверенным, что снаружи значение не изменится (для const ссылок такой уверенности нет).

TB>В С++ это не так, в Русте это так за счёт борзочекара.


В Rust учли опыт C++, к счастью.
Re[53]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 14:31
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>·>А если указатель?

TB>Можно использовать указатель как ключ, почему б и нет.
Сравнивать надо указуемое, а не значение указателя. Иначе ты тупо извлечь ничего из мапы не сможешь.

TB>·>А если массив является ключом в двух разных мапах?

TB>Тогда копировать, да.
Ага-ага. Память — не ресурс.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[57]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 14:58
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Да, borrow checker нужен для нормальной реализации константности. Иначе полумеры.

s> В D сделали иммутабельность и без borrow checker-а.
Так я про константность. Не путай. Иммутабельность и в яве давно есть в виде records.

s> ·>Я имею в виду не бизнес-задачи, а задачи манипуляции кодом. Почему, например, перенос метода между классами _должно_ быть сложной задачей?

s> А это сложная задача?
Если это делать без поддержки IDE, то менять вручную сотни мест — может быть очень сложно. И это ведь не единственный доступный рефакторинг.

s> s>> "Отучаемся говорить за всех" (с)

s> ·>Ну вот видишь, нетривиальный borrow checker ещё как-то может это решить. А не этот ваш const.
s> Так у нас в C++ хотя бы const есть, а в Java и этого нет.
Ты не убедил, что он таки нужен в java, там есть другие средства.

s> ·>Так это просто неявный интерфейс, вот и всё.

s> Может вам матчасть подучить?
Если ты будешь придираться к тому, что константный объект и константная ссылка на объект — не одно и то же, то пофиг, не в этом суть, а в практике. Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.

s> s>> И это изкаропки и бесплатно.

s> ·>Как и интерфейсы в java.
s> Так уже выяснили, что интерфейсы Java к константности отношения не имеют. Просто привыкли жрать что дали и научились получать удовольствие.
Они могут создавать константное представление объекта для использования в других местах. Т.е. в качестве этой роли их можно использовать.

s> ·>Состояние объекта меняется.

s> ·>может иметь разный результат.
s> А кто сказал, что getX имеет отношение к состоянию объекта? Стиль наименования как в Java?
Не понял вопрос.

s> ·>А иммутабельность гарантирует, что результат будет одинаковый, не смотря ни на что.

s> Ну и в C++ у нас есть помощь со стороны компилятора в ее обеспечении, в отличии от.
В java есть records.

s> ·>А зачем иметь queue константную, чтобы что?

s> Чтобы показать, что в C++ константой можно сделать даже то, что на такую роль и не предполагалось.
А дальше что с этой константой делать?

s> ·>А в плюсах как иммутабельность делать?

s> Поверить тому, что переданное по константной ссылке и есть константа.
Гы. "Поверить". Ясно... Правильно, без веры, молитвы, да чистого сердца разве можно код писать?!

s> ·>Иммутабельность — полезная вещь. Константность — очень спорная полезность.

s> Вам бы еще понять, что в нормальных языках константность на уровне языка сильно помогает в достижении иммутабельности. Но с этим пониманием явно проблемы, mind-set полагаю, плюс отсутствие воображения.
Константность — не помогает. Иммутабельность помогает, как record в java.

s> ·>Можешь считать, что в java просто умолчание другое — все поля mutable по дефолту, кроме обозначенных final.

s> Вы бы уяснили себе, что final в Java запрещает присвоить новое значение ссылке. И не более того. А то мне, как C++нику, как-то совестно об этом вам напоминать.
А более и не надо.

s> ·>Ах да, конечно, бедность — не порок.

s> Нет, просто языки делались людьми для людей, а не для заработка на индусах разных национальностей.
Бедные, но очень гордые.

s> s>> Или не будет.

s> ·>"Работает — не трожь" mind-set?
s> Нет, вы не поняли. Не будет дорогой ошибкой если придется потом что-то поменять.
Как сделать банальное переименование в сотне файлов за 1 секунду? Только про search&replace не рассказывай.

s> ·>"Обычные", в смысле не API. Что ты под этим подразумеваешь — не знаю.

s> Обычные -- это такие, в которых нет суровых требований к сложности/ресурсоемкости/производительности. Вне зависимости от того, бэкэнд это, GUI, CLI или еще что-то.
И? Поменять смысл слова — не годится в качестве контраргумента моим высказываниям.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[54]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 14:58
Оценка:
Здравствуйте, rg45, Вы писали:

r> TB>·>А если массив является ключом в двух разных мапах?

r> TB>Тогда копировать, да.
r> Тут могут быть варианты — в качестве ключей можно использовать указатели и std::reference_wrapper-ы с кастомными хэшерами/компараторами.
Верно. Но тогда пропадает "защита" от изменений ключа в мапе, которую обещает T4r4sB.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[55]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 15:03
Оценка:
Здравствуйте, ·, Вы писали:

·>Верно. Но тогда пропадает "защита" от изменений ключа в мапе, которую обещает T4r4sB.


Почему это? И ссылка и указатель могут быть константными (ссылаться на константные данные, если быть более точным):

std::map<const int*, Foo, CustomComparer>;
std::map<const (*int)[42], Foo, CustomComparer>;
std::map<std::reference_wrapper<const int[42]>, Foo, CustomComparer>;


Так что, это уж как захочет программист
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 13.05.2023 15:25 rg45 . Предыдущая версия . Еще …
Отредактировано 13.05.2023 15:15 rg45 . Предыдущая версия .
Re[54]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 15:31
Оценка:
Здравствуйте, ·, Вы писали:

TB>>Можно использовать указатель как ключ, почему б и нет.

·>Сравнивать надо указуемое, а не значение указателя. Иначе ты тупо извлечь ничего из мапы не сможешь.

Без проблем — для этого предусмотренa возможность кастомизации хэшеров и компараторов: std::map, std::unordered_map.
--
Справедливость выше закона. А человечность выше справедливости.
Re[56]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 15:40
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>·>Верно. Но тогда пропадает "защита" от изменений ключа в мапе, которую обещает T4r4sB.

R>Почему это? И ссылка и указатель могут быть константными (сслаться на константные данные, если быть более точным):
Потому. Ты тоже не понимаешь разницу между константностью и иммутабельностью?
R>std::map<std::reference_wrapper<const int[42]>, Foo, CustomComparer>;

Давай попробуем:

std::map<std::reference_wrapper<const int>, std::string> map;
int key = 42;
map[key]= "hi";
key++; //упс! Мапа сломана.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[55]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 15:42
Оценка:
Здравствуйте, rg45, Вы писали:

TB>>>Можно использовать указатель как ключ, почему б и нет.

R>·>Сравнивать надо указуемое, а не значение указателя. Иначе ты тупо извлечь ничего из мапы не сможешь.
R>Без проблем — для этого предусмотренa возможность кастомизации хэшеров и компараторов: std::map, std::unordered_map.
Дело не в этом. А в том, что указуемое может меняться независимо от мапы и нарушить инвариант.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[56]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 15:49
Оценка: +1
Здравствуйте, ·, Вы писали:

·>Дело не в этом. А в том, что указуемое может меняться независимо от мапы и нарушить инвариант.


Все правильно, может. Потому что константность ссылки/указателя не гарантируют неизменности адресуемых данных. И тем не менее, программист МОЖЕТ обеспечить реальную константность адресуемых данных. И в этом случае их неизменность будет гарантирована в well-defined программе. Короче говоря, да, в этой области больше возможностей выстрелить себе в ногу. Но и возможность писать добротные надежные программы тоже есть.
--
Справедливость выше закона. А человечность выше справедливости.
Re[57]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 15:56
Оценка: -1
Здравствуйте, rg45, Вы писали:

R>·>Дело не в этом. А в том, что указуемое может меняться независимо от мапы и нарушить инвариант.

R>Все правильно, может. Потому что константность ссылки/указателя не гарантируют неизменности адресуемых данных. И тем не менее, программист МОЖЕТ обеспечить реальную константность адресуемых данных. И в этом случае их неизменность будет гарантирована в well-defined программе. Короче говоря, да, в этой области больше возможностей выстрелить себе в ногу. Но и возможность писать добротные надежные программы тоже есть.
Я это прекрасно знаю. Ровно то же и в java. Просто T4r4sB заявил
Автор: T4r4sB
Дата: 12.05.23
, что в C++ есть какая-то защита в виде const. Да не даёт const ровным счётом ничего. Только если либо копия передаётся, либо передача ownership, и это немного помогает в некоторых случаях, но возможностей стрельнуть в ногу всё равно дофига.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[58]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 13.05.23 15:58
Оценка:
Здравствуйте, ·, Вы писали:

s>> ·>Да, borrow checker нужен для нормальной реализации константности. Иначе полумеры.

s>> В D сделали иммутабельность и без borrow checker-а.
·>Так я про константность. Не путай.

Матчасть, матчасть!

·>Если это делать без поддержки IDE, то менять вручную сотни мест — может быть очень сложно.


А может и не быть.

·>Ты не убедил, что он таки нужен в java, там есть другие средства.


Вы думаете, что вас кто-то в чем-то убеждал? Полноте. Поржать над тем, как с удовольствием жрут убожество, да еще и причмокивают, -- это запросто. А вот убеждать...

s>> ·>Так это просто неявный интерфейс, вот и всё.

s>> Может вам матчасть подучить?
·>Если ты будешь придираться к тому, что константный объект и константная ссылка на объект — не одно и то же

Не одно.

·>, то пофиг, не в этом суть


Да ну?

·>, а в практике.


А, ну да.

·>Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.


Во-первых, могу передать по значению.

Во-вторых, константные ссылки могут быть на неконстантные объекты. Поэтому не нужно путать теплое с мягким. Хотя без знания матчасти это сложно, да.

·>Они могут создавать константное представление объекта для использования в других местах.


Это никак не контролируется компилятором. Это раз.
Это все порождает новые сущности. Это два.
И все, можно закапывать.

·>Не понял вопрос.


Вопрос в том, что с чего вы взяли, что вызов метода getX имеет какое-то отношение к состоянию объекта.
Но это риторический вопрос.

s>> ·>А иммутабельность гарантирует, что результат будет одинаковый, не смотря ни на что.

s>> Ну и в C++ у нас есть помощь со стороны компилятора в ее обеспечении, в отличии от.
·>В java есть records.

HashMap в Java -- это records? Как вы получите константный HashMap в Java?

s>> ·>А зачем иметь queue константную, чтобы что?

s>> Чтобы показать, что в C++ константой можно сделать даже то, что на такую роль и не предполагалось.
·>А дальше что с этой константой делать?

Например, разделить между тредами.

s>> ·>А в плюсах как иммутабельность делать?

s>> Поверить тому, что переданное по константной ссылке и есть константа.
·>Гы. "Поверить". Ясно... Правильно, без веры, молитвы, да чистого сердца разве можно код писать?!

Ну вы же в Java пишете интерфейсы и верите в то, что в их реализации никто ничего не модифицирует. Нам-то почему нельзя?

·>Константность — не помогает.


Так вы же ее готовить не умеете.

s>> Вы бы уяснили себе, что final в Java запрещает присвоить новое значение ссылке. И не более того. А то мне, как C++нику, как-то совестно об этом вам напоминать.

·>А более и не надо.

Поциент безнадежен, так и запишем.
Re[58]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 15:59
Оценка:
Здравствуйте, ·, Вы писали:

·>Да не даёт const ровным счётом ничего.


Ну вот на этот счет у меня немного другое мнение. То, что он не гарантирует неизменности объектна, не означает, что он не дает НИЧЕГО. Это защита от непреднамеренного ошибочного изменения данных. А относительно примера, который ты привел выше — программист должен понимать опасность такого дизайна. И если даже такое где-то встрется, то, наверное, это следует рассматривать как какую-то вынужденную исключительную меру, а не как общий случай. Да, способов выстрелить себе в ногу в C++ больше, чем в других языках. По-моему, это ни для кого не секрет.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 13.05.2023 16:04 rg45 . Предыдущая версия . Еще …
Отредактировано 13.05.2023 16:03 rg45 . Предыдущая версия .
Отредактировано 13.05.2023 16:02 rg45 . Предыдущая версия .
Re[58]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 13.05.23 16:42
Оценка: +1
Здравствуйте, ·, Вы писали:

·>... Да не даёт const ровным счётом ничего. Только если либо копия передаётся, либо передача ownership, и это немного помогает в некоторых случаях, но возможностей стрельнуть в ногу всё равно дофига.


Например некоторый случай
Re[59]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 17:14
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Так я про константность. Не путай.

S>Матчасть, матчасть!
Угу. Разберись. Вопросы-то какие возникли?

S>·>Если это делать без поддержки IDE, то менять вручную сотни мест — может быть очень сложно.

S>А может и не быть.
Давай, просвети: Как сделать банальное переименование в сотне файлов за 1 секунду? Только про search&replace не рассказывай. И про регекспы я тоже знаю.

s>>> ·>Так это просто неявный интерфейс, вот и всё.

s>>> Может вам матчасть подучить?
S>·>Если ты будешь придираться к тому, что константный объект и константная ссылка на объект — не одно и то же
S>Не одно.
Я знаю. Только рояли в нашем случае не играет.

S>·>Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.

S>Во-первых, могу передать по значению.
Ох, да. Я забыл. "Память — не ресурс!" — девиз С++. Я ничего не попутал?
А вообще если ты передаёшь по значению, то с таким же успехом можно передавать и неконстантный объект.

S>Во-вторых, константные ссылки могут быть на неконстантные объекты. Поэтому не нужно путать теплое с мягким. Хотя без знания матчасти это сложно, да.

Угу. Только причём тут константные объекты за которых ты так топишь? Выделил выше, чтобы ты контекст не терял.

S>·>Они могут создавать константное представление объекта для использования в других местах.

S>Это никак не контролируется компилятором. Это раз.
Как и в плюсах.

S>Это все порождает новые сущности. Это два.

Не порождает. А наоборот, уменьшает. Я тебе уже объяснял — вместо двух полных имплементаций методов const/non-const у тебя будет только сигнатура дважды — в классе и в интерфейсе.

S>И все, можно закапывать.

Да, бери лопату.

S>·>Не понял вопрос.

S>Вопрос в том, что с чего вы взяли, что вызов метода getX имеет какое-то отношение к состоянию объекта.
Состояние объекта обнаруживается по результату операций с ним. Иммутабельный объект имеет неизменное внешнее состояние. И getX обязан выдавать один и тот же результат вне зависимости от когда или где он был вызван.

s>>> ·>А иммутабельность гарантирует, что результат будет одинаковый, не смотря ни на что.

s>>> Ну и в C++ у нас есть помощь со стороны компилятора в ее обеспечении, в отличии от.
S>·>В java есть records.
S>HashMap в Java -- это records? Как вы получите константный HashMap в Java?
Map.ofEntries(entry(1, "a"), entry(2, "b"));

s>>> Чтобы показать, что в C++ константой можно сделать даже то, что на такую роль и не предполагалось.

S>·>А дальше что с этой константой делать?
S>Например, разделить между тредами.
Это как? Ты можешь разделить либо ссылку между тредами (без возможности защитить ссылаемое от изменений), либо копию (память — не ресурс).

S>·>Гы. "Поверить". Ясно... Правильно, без веры, молитвы, да чистого сердца разве можно код писать?!

S>Ну вы же в Java пишете интерфейсы и верите в то, что в их реализации никто ничего не модифицирует. Нам-то почему нельзя?
Верим. Просто вы ещё и привираете, что компилятор вас спасает и сохраняет благодаря молитве "const".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[59]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 18:08
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>·>... Да не даёт const ровным счётом ничего. Только если либо копия передаётся, либо передача ownership, и это немного помогает в некоторых случаях, но возможностей стрельнуть в ногу всё равно дофига.


_>Например некоторый случай


Компилятор имеет право воспринимать происходящее следующим образом:
В векторе 1 элемент
Вектор не реаллоцировался.
Указатель на элемет в первом cout и во втором cout один и тот же.
И там и там используется константное поле
Я его уже читал при первом cout
Зачем мне его читать еще раз, это же константа!
Вывожу закэшированное значение.


Бред собачий. Не имеет права компилятор так воспринимать происходящее. Вектор неконстантный и он модифицировался. Была реллокация или нет — это насрать. Более того, в этом случае используется даже неконстантная версия метода back, которая возвращает неконстантную ссылку на элемент вектора. Поводов для описанной оптимизации здесь нет от слова "совсем". Если какой-то компилятор так делает, то это просто баг. Это во-первых. А во-вторых, а какой компилятор так делает — пруфы будут?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 13.05.2023 18:58 rg45 . Предыдущая версия . Еще …
Отредактировано 13.05.2023 18:20 rg45 . Предыдущая версия .
Отредактировано 13.05.2023 18:09 rg45 . Предыдущая версия .
Re[59]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 13.05.23 19:11
Оценка:
Здравствуйте, rg45, Вы писали:

r> ·>Да не даёт const ровным счётом ничего.

r> Ну вот на этот счет у меня немного другое мнение. То, что он не гарантирует неизменности объектна, не означает, что он не дает НИЧЕГО. Это защита от непреднамеренного ошибочного изменения данных. А относительно примера, который ты привел выше — программист должен понимать опасность такого дизайна. И если даже такое где-то встрется, то, наверное, это следует рассматривать как какую-то вынужденную исключительную меру, а не как общий случай. Да, способов выстрелить себе в ногу в C++ больше, чем в других языках. По-моему, это ни для кого не секрет.
Разговор был начат, что без const жизнь не мила, и другие языки страдают от его отсутствия.
Конечно, что-то он даёт. Но то что он даёт — делается например, в той же java с помощью интерфейсов, которые дают ещё много чего интересного.
Т.е. я имел в виду, что не даёт ровным счётом ничего по сравнению с другими подходами.

Я бы сказал что он даже немножечко вредит. Вон тут сколько народу, прожжённых плюсовиков вроде как, а запутались в трёх соснах, и не видят где можно выстрелить себе в ногу.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[60]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 13.05.23 19:16
Оценка: :)
Здравствуйте, ·, Вы писали:

·>Разговор был начат, что без const жизнь не мила, и другие языки страдают от его отсутствия.

·>Конечно, что-то он даёт. Но то что он даёт — делается например, в той же java с помощью интерфейсов, которые дают ещё много чего интересного.
·>Т.е. я имел в виду, что не даёт ровным счётом ничего по сравнению с другими подходами.
·>Я бы сказал что он даже немножечко вредит. Вон тут сколько народу, прожжённых плюсовиков вроде как, а запутались в трёх соснах, и не видят где можно выстрелить себе в ногу.

Ну, холиварьте потихоньку. Меня только не втягивайте
--
Справедливость выше закона. А человечность выше справедливости.
Re[60]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 08:22
Оценка:
Здравствуйте, ·, Вы писали:

S>>·>Так я про константность. Не путай.

S>>Матчасть, матчасть!
·>Угу. Разберись.

Ну я то наслышан и о том, как оно в C++, и как оно в D. Это вы здесь пытаетесь лепить горбатого.

·>Вопросы-то какие возникли?


Да. Например: вы всегда настолько интеллектуальны или только в тредах про C++?

·>Давай, просвети: Как сделать банальное переименование в сотне файлов за 1 секунду? Только про search&replace не рассказывай.


Давай, расскажи мне как переслать деньги человеку в другой город, только про почтовые переводы и переводы с карты на карту не рассказывай.

Тупить еще не надоело?

S>>·>Если ты будешь придираться к тому, что константный объект и константная ссылка на объект — не одно и то же

S>>Не одно.
·>Я знаю.

А почему этого не видно?

·>Только рояли в нашем случае не играет.


Еще как играет. Константного объекта нет.

S>>·>Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.

S>>Во-первых, могу передать по значению.
·>Ох, да. Я забыл. "Память — не ресурс!" — девиз С++. Я ничего не попутал?

Попутали и много чего. Берега в первую очередь. Как и здравый смысл.

·>А вообще если ты передаёшь по значению, то с таким же успехом можно передавать и неконстантный объект.


Если только передавать, то с таким же успехом. Только вот в случае:
const A a;
... // (1)
f(a);

В точке (1) компилятор бьет меня по рукам за попытки модифицировать `a`. В случае неконстантного объекта никакого контроля нет. И по мере развития кода в точке (1) может произойти непреднамеренная модификация.

S>>Во-вторых, константные ссылки могут быть на неконстантные объекты. Поэтому не нужно путать теплое с мягким. Хотя без знания матчасти это сложно, да.

·>Угу. Только причём тут константные объекты за которых ты так топишь?

Если я вас до сих пор не смог объяснить, то дальше не стоить и пытаться. Мне за ваше образование не платят.

S>>Это никак не контролируется компилятором. Это раз.

·>Как и в плюсах.

Можно было бы в очередной раз отправить вас учить матчасть, но это, увы, бесполезно. Так что вопрос о вашем интеллектуальном уровне становится еще более актуальным.

S>>Это все порождает новые сущности. Это два.

·>Не порождает.

Главное верить. Ведь новые сущности в дополнение к классу -- это не новые сущности, это вообще ничто. Суслик наоборот: их видят, но их нет. Ага.

·>Я тебе уже объяснял — вместо двух полных имплементаций методов const/non-const


Вы вообще C++ видели? Необходимость делать const/non-const методы возникает очень редко и в специфических случаях. Например, когда вы реализуете контейнеры или builder pattern. И то, и другое можно отнести к разработке библиотек. В прикладном коде const и non-const версия одного и того же метода -- это экзотика.

·>Состояние объекта обнаруживается по результату операций с ним. Иммутабельный объект имеет неизменное внешнее состояние. И getX обязан выдавать один и тот же результат вне зависимости от когда или где он был вызван.


С чего бы он был обязан? С того, что вы привыкли к такому соглашению об именовании?

S>>HashMap в Java -- это records? Как вы получите константный HashMap в Java?

·>Map.ofEntries(entry(1, "a"), entry(2, "b"));

И вам не стыдно?

The Map.of, Map.ofEntries, and Map.copyOf static factory methods provide a convenient way to create unmodifiable maps. The Map instances created by these methods have the following characteristics:

* They are unmodifiable. Keys and values cannot be added, removed, or updated. Calling any mutator method on the Map will always cause UnsupportedOperationException to be thrown.


Вам возвращается не HashMap, а некая непонятная реализация интерфейса Map. Для которой компилятор не может проверить, модифицируете ли вы возвращенный экземпляр или нет. Вы спокойно можете вызывать мутирующие методы и будете разбираться с проблемами в run-time.

Ахренеть, дайте два!

·>Это как? Ты можешь разделить либо ссылку между тредами (без возможности защитить ссылаемое от изменений)


Объект константный, его не нужно защищать.

·>Верим. Просто вы ещё и привираете, что компилятор вас спасает и сохраняет благодаря молитве "const".


Да, получение ошибки от компилятора -- это "привираете". Дяденька, да вы поехавший.
Re[60]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 08:40
Оценка:
Здравствуйте, ·, Вы писали:

·>Разговор был начат, что без const жизнь не мила, и другие языки страдают от его отсутствия.


Вы попутали. Не другие языки страдают, а при переходе на другие языки ощущается отсутствие const. Т.е. страдают не языки, а разработчики. По крайней мере те, кто научились const использовать себе во благо.
Re[61]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 09:25
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Разговор был начат, что без const жизнь не мила, и другие языки страдают от его отсутствия.

S>Вы попутали. Не другие языки страдают,
Не попутал. Просто выразился другими словами. Думаю всем очевидно, что ЯП — вещь неодушевлённая и страдать сам по себе не может.

S>а при переходе на другие языки ощущается отсутствие const. Т.е. страдают не языки, а разработчики. По крайней мере те, кто научились const использовать себе во благо.

Это верно. Я сам таким был, я уже это говорил. Но это не беда. Беда в том, что некоторые (не будем показывать пальцем) такие разработчики почему-то необоснованно обобщают и считают, что это не их субъективное восприятие, сила привычки, а объективная проблема дизайна языка, которую ощущают все разработчики, даже те, кто освоили такой ЯП на профессиональном уровне.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[62]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 09:35
Оценка:
Здравствуйте, ·, Вы писали:

·>Думаю всем очевидно, что ЯП — вещь неодушевлённая и страдать сам по себе не может.


У языка могут быть объективные недостатки (вроде недостаточность выразительных возможностей, недостаточно строгая типизация, недостаточная безопасность (отсутствие тех или иных гарантий/проверок) и т.д., и т.п.) из-за которых вполне можно говорить, что "страдает язык".

Например, чистый C страдает от ущербности. А C++ от сложности. Они оба страдают от небезопасности.

·>Беда в том, что некоторые (не будем показывать пальцем) такие разработчики почему-то необоснованно обобщают и считают, что это не их субъективное восприятие, сила привычки, а объективная проблема дизайна языка, которую ощущают все разработчики


Вы и цитатой сможете это подтвердить? Особенно утверждения про "проблему дизайна, которую ощущают все разработчики".
Re[63]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 09:55
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Думаю всем очевидно, что ЯП — вещь неодушевлённая и страдать сам по себе не может.

S>У языка могут быть объективные недостатки (вроде недостаточность выразительных возможностей, недостаточно строгая типизация, недостаточная безопасность (отсутствие тех или иных гарантий/проверок) и т.д., и т.п.) из-за которых вполне можно говорить, что "страдает язык".
S>Например, чистый C страдает от ущербности. А C++ от сложности. Они оба страдают от небезопасности.
Ок. Принято. Я под страданием ЯП понимал именно страдание тех, кто его использует.

S>·>Беда в том, что некоторые (не будем показывать пальцем) такие разработчики почему-то необоснованно обобщают и считают, что это не их субъективное восприятие, сила привычки, а объективная проблема дизайна языка, которую ощущают все разработчики

S>Вы и цитатой сможете это подтвердить? Особенно утверждения про "проблему дизайна, которую ощущают все разработчики".
https://rsdn.org/forum/cpp/8526192
Автор: so5team
Дата: 12.05.23

Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?

В такой формулировке вопрос подразумевает, что это недостаток от которого плохо всем разработчикам. Возможно, я не так понял.
Я предложил интерфейсы, final, records, тебя не устроило. И пытаешься доказать, что мною предолженное проблему не решает. Ты ожидаешь прямую замену const, а на самом деле ЯП просто подразумевает другие подходы и поэтому проблема не ощущается вообще никак.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[64]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 10:16
Оценка:
Здравствуйте, ·, Вы писали:

S>>Вы и цитатой сможете это подтвердить? Особенно утверждения про "проблему дизайна, которую ощущают все разработчики".

·>https://rsdn.org/forum/cpp/8526192
Автор: so5team
Дата: 12.05.23

·>

Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?

·>В такой формулировке вопрос подразумевает, что это недостаток от которого плохо всем разработчикам.

Когда речь про "ощущают" то нужно, чтобы разработчики понимали что у них есть, а чего они лишены.
Для меня очевидно, что далеко не все разработчики на Java (а так же упомянутых в том сообщении Ruby и Python) осознают что дает дополнительный контроль со стороны компилятора. А раз не осознают, что вряд ли и ощущают.

·>Я предложил интерфейсы, final, records, тебя не устроило. И пытаешься доказать, что мною предолженное проблему не решает.


Так это очевидно, что не решают. Вы же привели пример с Map.ofEntities, который возвращает экземпляр интерфейса Map, но как только мы удаляемся от вызова Map.ofEntities, то нам не видно, скрывается ли за этим Map-ом мутабельный или иммутабельный объект (unmodifiable в терминологии из Java Doc). Соответственно, ничто в compile-time не мешает вызвать нам у этого Map-а мутирующий метод.

Когда как в языках с поддежкой константности (C++, D, Rust) мы могли бы иметь const (или immutable в D) экземпляр, у которого нельзя было бы вызывать мутирующие методы и это бы проверялось в compile-time.

Собственно, об этом и шла речь, что разбираться с тем, что мутабельно, а что нет, в C++ оказывается проще (для меня), чем в Java, Ruby или Python.
Re[61]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 11:13
Оценка:
Здравствуйте, so5team, Вы писали:

S>>>Матчасть, матчасть!

S>·>Угу. Разберись.
S>Ну я то наслышан и о том, как оно в C++, и как оно в D. Это вы здесь пытаетесь лепить горбатого.
Но слушать не хочешь как в других яп.

S>·>Давай, просвети: Как сделать банальное переименование в сотне файлов за 1 секунду? Только про search&replace не рассказывай.

S>Давай, расскажи мне как переслать деньги человеку в другой город, только про почтовые переводы и переводы с карты на карту не рассказывай.
Отличная аналогия. Ты не поверишь: я в жизни не пользовался ни почтовым переводом, ни переводом между картами.
А вот ты и знать не хочешь, что другие способы перевода существуют, в том числе и более современные, быстрые и/или надёжные. Например, можно просто урл мессагой послать. Или по номеру мобильника. Или чек курьером отправить. Или запейпалить. Или биток скинуть. И т.п. Но ты упорно пытаешься доказать, что без почтового перевода или карт настоящие шотландцы переводы невозможны.

S>Тупить еще не надоело?

Надоело. Кончай уже.

S>·>Я знаю.

S>А почему этого не видно?
Потому что:
S>·>Только рояли в нашем случае не играет.

S>Еще как играет. Константного объекта нет.

Если бы и был, проблему не решает.

S>>>Во-первых, могу передать по значению.

S>·>Ох, да. Я забыл. "Память — не ресурс!" — девиз С++. Я ничего не попутал?
S>Попутали и много чего. Берега в первую очередь. Как и здравый смысл.
Так всё-таки. Не съезжай темы. Как _сам_ константный объект куда-нибудь передать?

S>·>А вообще если ты передаёшь по значению, то с таким же успехом можно передавать и неконстантный объект.

S>Если только передавать, то с таким же успехом. Только вот в случае:
S>В точке (1) компилятор бьет меня по рукам за попытки модифицировать `a`. В случае неконстантного объекта никакого контроля нет. И по мере развития кода в точке (1) может произойти непреднамеренная модификация.
Именно. Лучшее что можно сделать с константным объектом — иметь его внутри одного метода и никуда больше. Вот только толку всё равно мало. Насколько это важно и необходимо — у меня большие сомнения.
Как правило наоборот, в пределах одного метода объекты требуется пилить и кромсать. А наружу выдавать безопасный результат.
Увидеть что объект меняется в пределах одного метода — легко. Вот и получается, что если const что и помогает решить, так это какую-то тривиальную проблему. Зато цена этого — значительное усложнеие всего яп и кода.

S>>>Во-вторых, константные ссылки могут быть на неконстантные объекты. Поэтому не нужно путать теплое с мягким. Хотя без знания матчасти это сложно, да.

S>·>Угу. Только причём тут константные объекты за которых ты так топишь?
S>Если я вас до сих пор не смог объяснить, то дальше не стоить и пытаться. Мне за ваше образование не платят.
Я сказал конкретно: "Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.". Ты начал говорить про defensive copy и "неконстантные объекты". Зачем мне такое образование в софизмах?

S>>>Это все порождает новые сущности. Это два.

S>·>Не порождает.
S>Главное верить. Ведь новые сущности в дополнение к классу -- это не новые сущности, это вообще ничто. Суслик наоборот: их видят, но их нет. Ага.
Какие _новые_? был const, стал интерфейс. Это замена, а не новое. Шило на мыло.

S>·>Я тебе уже объяснял — вместо двух полных имплементаций методов const/non-const

S>Вы вообще C++ видели? Необходимость делать const/non-const методы возникает очень редко и в специфических случаях. Например, когда вы реализуете контейнеры или builder pattern. И то, и другое можно отнести к разработке библиотек. В прикладном коде const и non-const версия одного и того же метода -- это экзотика.
А что ты подразумевал под some_application_domain_type? Пример приведи, где там будет const/non-const?

S>·>Состояние объекта обнаруживается по результату операций с ним. Иммутабельный объект имеет неизменное внешнее состояние. И getX обязан выдавать один и тот же результат вне зависимости от когда или где он был вызван.

S>С чего бы он был обязан? С того, что вы привыкли к такому соглашению об именовании?
Причём тут именование? У record именование будет просто x(). Обязан как следсвтие иммутабелности — если состояние не меняется, то оно неразличимо в любой момент времени.

S>>>HashMap в Java -- это records? Как вы получите константный HashMap в Java?

S>·>Map.ofEntries(entry(1, "a"), entry(2, "b"));
S>И вам не стыдно?
Я думал, что ты уже понял, что ровно той же константности, что есть плюсах в java нет. Есть практические задачи и механизмы их решения.
Надо рассматривать конкретный сценарий и тогда можно говорить о разных подходах как писать хороший код, какие механизмы ЯП использовать.
В данном случае я вам предложил неизменяемую мапу, которая может быть безопасно передана в другие треды и т.п.
Зачем конкретно вам нужен HashMap неясно. Ведь если подумать, то внезапно выяснится, что если у тебя есть конкретные данные, то HashMap может быть не нужен. Например, если у тебя мапа размером 1, то нет никакого смысла создавать HashMap c fillfactor, резервировать бакеты и т.п., эффективнее иметь специальную реализацию мапы размером 1. Этим Map.of и занимается.

S>

The Map.of, Map.ofEntries, and Map.copyOf static factory methods provide a convenient way to create unmodifiable maps. The Map instances created by these methods have the following characteristics:
S>* They are unmodifiable. Keys and values cannot be added, removed, or updated. Calling any mutator method on the Map will always cause UnsupportedOperationException to be thrown.

Потому что это immutable.
S>Вам возвращается не HashMap, а некая непонятная реализация интерфейса Map. Для которой компилятор не может проверить, модифицируете ли вы возвращенный экземпляр или нет. Вы спокойно можете вызывать мутирующие методы и будете разбираться с проблемами в run-time.
Так ведь всё то же самое:
void some(const std::map<..> &data)
{
  validateData(data);
  callSomething();// были ли тут вызваны мутирующие методы data? Разбирайся в run-time
  useData(data);// здесь у нас та же data что выше или может быть уже другая, не та, которую мы провалидировали?
}

А с многопоточкой так ещё хуже. Так что иммутабельность — нужна, ибо решает вполне серьёзные проблемы. Константность — не нужна.

S>·>Это как? Ты можешь разделить либо ссылку между тредами (без возможности защитить ссылаемое от изменений)

S>Объект константный, его не нужно защищать.
Как выяснили константный объект невозможно передать между тредами.

S>·>Верим. Просто вы ещё и привираете, что компилятор вас спасает и сохраняет благодаря молитве "const".

S>Да, получение ошибки от компилятора -- это "привираете". Дяденька, да вы поехавший.
А вы хамите в очередной раз.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[65]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 11:24
Оценка:
Здравствуйте, so5team, Вы писали:

S>Когда речь про "ощущают" то нужно, чтобы разработчики понимали что у них есть, а чего они лишены.

Так я знаю. У меня несколько лет опыта на плюсах есть, правда давнего.

S>Для меня очевидно, что далеко не все разработчики на Java (а так же упомянутых в том сообщении Ruby и Python) осознают что дает дополнительный контроль со стороны компилятора. А раз не осознают, что вряд ли и ощущают.

Я уже писал о своих ощущениях во время перехода с плюсов на яву.

S>·>Я предложил интерфейсы, final, records, тебя не устроило. И пытаешься доказать, что мною предолженное проблему не решает.

S>Так это очевидно, что не решают. Вы же привели пример с Map.ofEntities, который возвращает экземпляр интерфейса Map, но как только мы удаляемся от вызова Map.ofEntities, то нам не видно, скрывается ли за этим Map-ом мутабельный или иммутабельный объект (unmodifiable в терминологии из Java Doc). Соответственно, ничто в compile-time не мешает вызвать нам у этого Map-а мутирующий метод.
Не мешает. Но не грозит неизвестными последствиями, как в случае веры в то, что наличие const защищает от изменений (на что, например, напоролись T4r4sB и rg45 тут
Автор: ·
Дата: 13.05.23
, а ведь наверняка у них опыта в плюсах поболее моего).

S>Когда как в языках с поддежкой константности (C++, D, Rust) мы могли бы иметь const (или immutable в D) экземпляр, у которого нельзя было бы вызывать мутирующие методы и это бы проверялось в compile-time.

S>Собственно, об этом и шла речь, что разбираться с тем, что мутабельно, а что нет, в C++ оказывается проще (для меня), чем в Java, Ruby или Python.
А ты всё ещё не понимаешь, что immutable != const.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[62]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 12:05
Оценка:
Здравствуйте, ·, Вы писали:

S>>Ну я то наслышан и о том, как оно в C++, и как оно в D. Это вы здесь пытаетесь лепить горбатого.

·>Но слушать не хочешь как в других яп.

Это вы про Java во множественном числе?
Так я программировал на Java (за деньги, т.е. профессионально), так что слегка наслышан тоже.

·>А вот ты и знать не хочешь


Сударь, у вас проблемы с квантором всеобщности. Вы говорили, что будут проблемы при переименовании. Я же не говорил, что их не будет. Я говорил о том, что их может и не быть. И таки да, во многих случаях простой search&replace работает без проблем.

S>>Еще как играет. Константного объекта нет.

·>Если бы и был, проблему не решает.

Какую такую проблему?

S>>>>Во-первых, могу передать по значению.

S>>·>Ох, да. Я забыл. "Память — не ресурс!" — девиз С++. Я ничего не попутал?
S>>Попутали и много чего. Берега в первую очередь. Как и здравый смысл.
·>Так всё-таки. Не съезжай темы. Как _сам_ константный объект куда-нибудь передать?

Темы передать константный объект и не было, это вы по ходу выдумали. Я говорил, что константный объект можно расшарить между тредами как пример.

Да, расшарить можно по константной ссылке. Если у вас константные ссылки вызывают проблемы, то я не виноват.

·>Именно. Лучшее что можно сделать с константным объектом — иметь его внутри одного метода и никуда больше.


Ох, ё. Хватит уже позориться.

·>Увидеть что объект меняется в пределах одного метода — легко.


Не всегда.

·>Зато цена этого — значительное усложнеие всего яп и кода.


Ох, ё. Ох, ё. Да const -- это одна из вещей, которая делает программирование не C++ проще. Может быть научиться пользоваться const-ом для кого-то сложно. Но, как показывает (мой) опыт, научить людей понимать указатели (да и ссылки тоже) бывает куда сложнее.

·>Я сказал конкретно: "Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.". Ты начал говорить про defensive copy и "неконстантные объекты". Зачем мне такое образование в софизмах?


Ну что мне делать, если вы выдвигаете идиотский тезис "Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало." и требуете от меня ведения дискуссии в рамках этой откровенной идиотии?

Для вас толку мало, OK, это зафиксировано. Вот только за всех не следует говорить.

·>Какие _новые_?


В C++ у нас был MyApplicationType с const и non-const методами. В случае `MyApplicationType&` и `const MyApplicationType&` мы все еще имеем один и тот же тип, но с разными органичениями.

В Java у нас был MyApplicationType, затем к нему добавились MyApplicationTypeMutableIface и MyApplicationTypeImmutableIface. Никаких новых сущностей, ага. Шило на мыло, понятненько.

·>А что ты подразумевал под some_application_domain_type? Пример приведи, где там будет const/non-const?


Да вот, хотя бы: https://github.com/Stiffstream/arataga/blob/master/arataga/acl_handler/first_chunk.hpp#L123-L168

·>Причём тут именование? У record именование будет просто x(). Обязан как следсвтие иммутабелности — если состояние не меняется, то оно неразличимо в любой момент времени.


Еще раз: у вас есть объект o, у которого вы вызываете метод getX. Схерали метод getX должен иметь непосредственное отношение к состоянию объекта o?

·>Я думал, что ты уже понял, что ровно той же константности, что есть плюсах в java нет.


Могу предположить, я об этом узнал задолго до того, как вы перешли с C++ на Java, года эдак с 1998-го.

·>Есть практические задачи и механизмы их решения.


Например, есть ссылка на Map и нужно понять, можно ее менять или нет.

·>Так ведь всё то же самое:

·>void some(const std::map<..> &data)
·>{
·> validateData(data);
·> callSomething();// были ли тут вызваны мутирующие методы data? Разбирайся в run-time

Вы опять путаете теплое с мягким. Это некорректное сравнение.

Сравнивать нужно:
void mutator(std::map<...> & data);
void reader(const std::map<...> & data);

std::map<...> data;
...
mutator(data); // Мутирующие методы data могли быть вызваны.
reader(data); // Если там кто-то дернул мутирующие методы через const_cast, то это преднамеренная диверсия.


·>А с многопоточкой так ещё хуже.


Не обязательно. It depends.

·>Так что иммутабельность — нужна, ибо решает вполне серьёзные проблемы. Константность — не нужна.


Вы еще не поняли, что иммутабельность можно пытаться обеспечить разными способами. Можно врукопашную, как в Java, когда у вас все на честном слове. Можно с помощью средств языка. В C++ таковыми являются const. Можно научиться использовать const себе во благо. А можно убеждать себя, что и без const можно жить. Можно, кто ж спорит. Но лучше с const

·>Как выяснили константный объект невозможно передать между тредами.


Ох, ё, три раза.

·>А вы хамите в очередной раз.


А вы тупить перестаньте.
Отредактировано 15.05.2023 12:11 so5team . Предыдущая версия .
Re[66]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 12:21
Оценка:
Здравствуйте, ·, Вы писали:

·>Не мешает.


О том вам и говорят.

·>Но не грозит неизвестными последствиями, как в случае веры в то, что наличие const защищает от изменений


Ну так и не нужно верить в то, чего нет.

const позволяет бить по рукам за попытки модифицировать объект по константной ссылке или указателю.

Это все, что мы имеем в C++. И это лучше, чем если бы мы даже этого не имели.

·>(на что, например, напоролись T4r4sB и rg45 тут
Автор: ·
Дата: 13.05.23
, а ведь наверняка у них опыта в плюсах поболее моего).


Боюсь, этот пример нужно обсуждать с ними, а не со мной. Я не понял, чего там хотели достичь.

·>А ты всё ещё не понимаешь, что immutable != const.


Повторю и здесь:

Вы еще не поняли, что иммутабельность можно пытаться обеспечить разными способами. Можно врукопашную, как в Java, когда у вас все на честном слове. Можно с помощью средств языка. В C++ таковыми являются const.

Re[63]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 13:28
Оценка:
Здравствуйте, so5team, Вы писали:

S>>>Ну я то наслышан и о том, как оно в C++, и как оно в D. Это вы здесь пытаетесь лепить горбатого.

S>·>Но слушать не хочешь как в других яп.
S>Это вы про Java во множественном числе?
Я отвечал на твой кокнретный вопрос "При программировании на Java... Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Ну я и предложил.

S>Так я программировал на Java (за деньги, т.е. профессионально), так что слегка наслышан тоже.

Если опыт был серьёзный, то тогда неясно откуда такое непонимание.

S>·>А вот ты и знать не хочешь

S>Сударь, у вас проблемы с квантором всеобщности. Вы говорили, что будут проблемы при переименовании. Я же не говорил, что их не будет. Я говорил о том, что их может и не быть. И таки да, во многих случаях простой search&replace работает без проблем.
Хреново он работает.

S>>>Еще как играет. Константного объекта нет.

S>·>Если бы и был, проблему не решает.
S>Какую такую проблему?
Защиты данных от нежелательных изменений. Даже кривой legacy подход с UnsupportedOperationException это позволяет.

S>>>·>Ох, да. Я забыл. "Память — не ресурс!" — девиз С++. Я ничего не попутал?

S>>>Попутали и много чего. Берега в первую очередь. Как и здравый смысл.
S>·>Так всё-таки. Не съезжай темы. Как _сам_ константный объект куда-нибудь передать?
S>Темы передать константный объект и не было, это вы по ходу выдумали. Я говорил, что константный объект можно расшарить между тредами как пример.
Как расшарить-то??! Ты рассказал как передать ссылку (хоть на константный, хоть не константный, что ломает всю идею на корню), либо defensive copy, за которую меня упрекал.

S>Да, расшарить можно по константной ссылке. Если у вас константные ссылки вызывают проблемы, то я не виноват.

Константная ссылка не делает данные константными.

S>·>Увидеть что объект меняется в пределах одного метода — легко.

S>Не всегда.
Если сложно разобраться что делает данный конкретный метод — это либо хреновый яп, либо хреново написанный метод.

S>·>Я сказал конкретно: "Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало.". Ты начал говорить про defensive copy и "неконстантные объекты". Зачем мне такое образование в софизмах?

S>Ну что мне делать, если вы выдвигаете идиотский тезис "Ты без ссылок твой константный объект даже как параметр не сможешь никуда передать, а значит толку в таком объекте мало." и требуете от меня ведения дискуссии в рамках этой откровенной идиотии?
Ты так и не рассказал как же _передать_ (копирование это не передача) константный объект куда-то, чтобы он там и оставался гарантированно константным (чтобы туда нельзя было передать неконстантный).

S>·>Какие _новые_?

S>В C++ у нас был MyApplicationType с const и non-const методами. В случае `MyApplicationType&` и `const MyApplicationType&` мы все еще имеем один и тот же тип, но с разными органичениями.
С т.з. системы типов C++ — типы разные, не выдумывай. Попробуй расскажи о принципиальной разнице "const MyApplicationType" и "ConstMyApplicationType" с практической точки зрения.

S>В Java у нас был MyApplicationType, затем к нему добавились MyApplicationTypeMutableIface и MyApplicationTypeImmutableIface. Никаких новых сущностей, ага. Шило на мыло, понятненько.

Зачем?! "MyApplicationType" и "ConstMyApplicationType". Было два, стало два.

S>·>А что ты подразумевал под some_application_domain_type? Пример приведи, где там будет const/non-const?

S>Да вот, хотя бы: https://github.com/Stiffstream/arataga/blob/master/arataga/acl_handler/first_chunk.hpp#L123-L168
Ну и? Что тут даёт const? От тут тупо не нужен. В java полный аналог будет:
class first_chunk_for_next_handler_t
{
    first_chunk_t chunk;
    int remaining_bytes;

    first_chunk_t chunk()
    {
        return this.chunk;
    }

    first_chunk_t giveaway_chunk()
    {
        var chunk = this.chunk;
        this.chunk = null;
        return chunk;
    }

    int remaining_bytes()
    {
        return remaining_bytes;
    }
}


S>·>Причём тут именование? У record именование будет просто x(). Обязан как следсвтие иммутабелности — если состояние не меняется, то оно неразличимо в любой момент времени.

S>Еще раз: у вас есть объект o, у которого вы вызываете метод getX. Схерали метод getX должен иметь непосредственное отношение к состоянию объекта o?
Результат метода зависит от состояния объекта.

S>·>Есть практические задачи и механизмы их решения.

S>Например, есть ссылка на Map и нужно понять, можно ее менять или нет.
Это средство, а не цель. Понять чтобы что? Методу по логике вещей qwerAsdf либо нужно менять Map, либо не нужно. Если не нужно — он менять не будет. А если нужно, то ты хоть тресни, он будет, вне зависимости что ты туда _желаешь_ передать. Придётся передавать то, что нужно, а не то что хочется.

S>·>Так ведь всё то же самое:

S>·>void some(const std::map<..> &data)
S>·>{
S>·> validateData(data);
S>·> callSomething();// были ли тут вызваны мутирующие методы data? Разбирайся в run-time
S>Вы опять путаете теплое с мягким. Это некорректное сравнение.
Это именно то что создаёт проблему, которую сложно искать.

S>Сравнивать нужно:

S>
S>std::map<...> data;
S>...
S>mutator(data); // Мутирующие методы data могли быть вызваны.
S>reader(data); // Если там кто-то дернул мутирующие методы через const_cast, то это преднамеренная диверсия.
S>

А это какую проблему решает? Если кто-то поменяет сигнатуру метода reader, то в этом месте это тупо всё тихо поломается. Глядя на этот код только — ничего сказать нельзя. Тебе нужно видеть все сигнатуры и верить, что эти сигнатуры не поменяются.
О const_cast я даже не заикаюсь. Взрываться всё и без него может. Если ты всё ещё не догадался как это происходит в случае callSomething() — могу рассказать. Я уже показывал аналог тут
Автор: ·
Дата: 13.05.23
, константа константой константу погоняет, а всё тихо сломалось.

S>·>А с многопоточкой так ещё хуже.

S>Не обязательно. It depends.
Конечно. Но совершенно не depends от const. Пользы от const — ноль в данном случае.

S>·>Так что иммутабельность — нужна, ибо решает вполне серьёзные проблемы. Константность — не нужна.

S>Вы еще не поняли, что иммутабельность можно пытаться обеспечить разными способами. Можно врукопашную, как в Java, когда у вас все на честном слове. Можно с помощью средств языка. В C++ таковыми являются const. Можно научиться использовать const себе во благо. А можно убеждать себя, что и без const можно жить. Можно, кто ж спорит. Но лучше с const
Не подходит const для реализации иммутабельности.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[67]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 13:44
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Но не грозит неизвестными последствиями, как в случае веры в то, что наличие const защищает от изменений

S>Ну так и не нужно верить в то, чего нет.
Да. А ты веришь что const от чего-то защищает.

S>const позволяет бить по рукам за попытки модифицировать объект по константной ссылке или указателю.

Только это ни от чего не защищает.

S>·>(на что, например, напоролись T4r4sB и rg45 тут
Автор: ·
Дата: 13.05.23
, а ведь наверняка у них опыта в плюсах поболее моего).

S>Боюсь, этот пример нужно обсуждать с ними, а не со мной. Я не понял, чего там хотели достичь.
Им казалось, что const защищает map от модификации значений ключей, и что благодаря этому инварианты map сломать нельзя. Как оказалось, им таки только казалось.

S>·>А ты всё ещё не понимаешь, что immutable != const.

S>Повторю и здесь:
S>

Вы еще не поняли, что иммутабельность можно пытаться обеспечить разными способами. Можно врукопашную, как в Java, когда у вас все на честном слове. Можно с помощью средств языка. В C++ таковыми являются const.

В С++ тоже всё на честном слове, но ещё заблуждение, что const от чего-то защищает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[64]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 14:32
Оценка:
Здравствуйте, ·, Вы писали:

·>Я отвечал на твой кокнретный вопрос "При программировании на Java... Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Ну я и предложил.


На что вам сказали, что этот подход не дает никаких иных гарантий, кроме "мамой клянусь". Так чтож вы так убиваетесь-то, вы так не убьетесь.

·>Если опыт был серьёзный, то тогда неясно откуда такое непонимание.


Непонимание того, что const-а в Java нет? Вы бы доказали, что такое недопонимание имеет место быть.

·>Хреново он работает.


А иногда вообще не работает. А иногда отлично работает.

S>>Какую такую проблему?

·>Защиты данных от нежелательных изменений.

Ох, ё, i-й раз.
const std::vector<std::string> immutable_data{ "Hello"s, "World"s };
immutable_data.push_back("!"s); // Да как так-то?!!! Да чтож это деется-то, а?


Не, ну реально хватит позориться.

·>Даже кривой legacy подход с UnsupportedOperationException это позволяет.


Только вот к возможностям языка это не имеет отношения.

·>Как расшарить-то??! Ты рассказал как передать ссылку (хоть на константный, хоть не константный, что ломает всю идею на корню), либо defensive copy, за которую меня упрекал.


Константную ссылку на константный объект. Какую идею это ломает Видимо, это что-то очень личное.

S>>Да, расшарить можно по константной ссылке. Если у вас константные ссылки вызывают проблемы, то я не виноват.

·> Константная ссылка не делает данные константными.

А где-то утверждается обратное? Хде?!!!

·>Если сложно разобраться что делает данный конкретный метод — это либо хреновый яп, либо хреново написанный метод.


Вы что, живете в стране розовых пони? Мне вот по работе приходится заглядывать в методы на сотни строк. Ничего хорошего в этом нет, но в объективной реальности это вот прям чуть ли не на каждом шагу.

·>Ты так и не рассказал как же _передать_ (копирование это не передача) константный объект куда-то, чтобы он там и оставался гарантированно константным (чтобы туда нельзя было передать неконстантный).


Я не утверждал про невозможность передать неконстанный объект по константной ссылке. Вы что-то путаете.

·>С т.з. системы типов C++ — типы разные, не выдумывай.


OK. Но сколько усилий нам нужно, чтобы получить эти разные типы?

·>Попробуй расскажи о принципиальной разнице "const MyApplicationType" и "ConstMyApplicationType" с практической точки зрения.


Это две разных сущности, существование которых нужно оправдать. А потом вспомнить про "не плодите сущности без надобности"

S>>В Java у нас был MyApplicationType, затем к нему добавились MyApplicationTypeMutableIface и MyApplicationTypeImmutableIface. Никаких новых сущностей, ага. Шило на мыло, понятненько.

·>Зачем?! "MyApplicationType" и "ConstMyApplicationType". Было два, стало два.

О да, стало сильно легче.

S>>·>А что ты подразумевал под some_application_domain_type? Пример приведи, где там будет const/non-const?

S>>Да вот, хотя бы: https://github.com/Stiffstream/arataga/blob/master/arataga/acl_handler/first_chunk.hpp#L123-L168
·>Ну и? Что тут даёт const?

Дает указание компилятору на то, что его можно вызывать по константной ссылке, так и по неконстантной.

·>От тут тупо не нужен.


Да что вы говорите! Кто бы мог подумать...

·>В java полный аналог будет:

·>
·>class first_chunk_for_next_handler_t
·>{
·>    int remaining_bytes()
·>    {
              // А потом кто-то с кривыми руками...
              remaining_bytes--;
·>        return remaining_bytes;
·>    }
·>}
·>


S>>Еще раз: у вас есть объект o, у которого вы вызываете метод getX. Схерали метод getX должен иметь непосредственное отношение к состоянию объекта o?

·>Результат метода зависит от состояния объекта.

Повторюсь: схерали?

·>Методу по логике вещей qwerAsdf либо нужно менять Map, либо не нужно. Если не нужно — он менять не будет.


Как это гарантировать средствами языка?

·>А это какую проблему решает?


Проблему понимания константности в C++.

·>Если кто-то поменяет сигнатуру метода reader, то в этом месте это тупо всё тихо поломается. Глядя на этот код только — ничего сказать нельзя. Тебе нужно видеть все сигнатуры и верить, что эти сигнатуры не поменяются.


Если сигнатуры меняются, то наличие const в нужных местах приводит к ошибкам компиляции.

·>Я уже показывал аналог тут
Автор: ·
Дата: 13.05.23
, константа константой константу погоняет, а всё тихо сломалось.


Так там нет константы. Вы опять не выучили матчасть.

S>>·>А с многопоточкой так ещё хуже.

S>>Не обязательно. It depends.
·>Конечно. Но совершенно не depends от const. Пользы от const — ноль в данном случае.

Ой, ё. А мужики-то и не знают!

·>Не подходит const для реализации иммутабельности.


У вас, давайте говорить определеннее.
Re[68]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 14:36
Оценка:
Здравствуйте, ·, Вы писали:

S>>·>Но не грозит неизвестными последствиями, как в случае веры в то, что наличие const защищает от изменений

S>>Ну так и не нужно верить в то, чего нет.
·>Да. А ты веришь что const от чего-то защищает.

От защищает от вызова методов, которые не помечены как const. И да, в это сложно не поверить, после того, как компилятор столько раз бил по рукам.

S>>const позволяет бить по рукам за попытки модифицировать объект по константной ссылке или указателю.

·>Только это ни от чего не защищает.

Да что вы говорите? И вам можно верить?

·>Им казалось, что const защищает map от модификации значений ключей, и что благодаря этому инварианты map сломать нельзя. Как оказалось, им таки только казалось.


Так в случае с reference_wrapper для const int там не было того самого const int.

Собственно, это одна из проблем с const& (и const*) о которой я вам раньше и говорил: они могут указывать на неконстантные данные.
Re[69]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 15:45
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Да. А ты веришь что const от чего-то защищает.

S>От защищает от вызова методов, которые не помечены как const.
Как и const-интерфейс. В чём поинт-то?

S>И да, в это сложно не поверить, после того, как компилятор столько раз бил по рукам.

С интерфейсом код такой написать тупо не получится, до компилятора дело даже не доходит.

S>>>const позволяет бить по рукам за попытки модифицировать объект по константной ссылке или указателю.

S>·>Только это ни от чего не защищает.
S>Да что вы говорите? И вам можно верить?
Правду. Конечно.

S>·>Им казалось, что const защищает map от модификации значений ключей, и что благодаря этому инварианты map сломать нельзя. Как оказалось, им таки только казалось.

S>Так в случае с reference_wrapper для const int там не было того самого const int.
Они не знали, ну ладно, будем считать забыли. Как и ты, когда предлагал мне константные ссылки передавать в другие треды.

S>Собственно, это одна из проблем с const& (и const*) о которой я вам раньше и говорил: они могут указывать на неконстантные данные.

Именно. Что и сводит на нет полезность константных объектов.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[70]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 16:12
Оценка:
Здравствуйте, ·, Вы писали:

S>>·>Да. А ты веришь что const от чего-то защищает.

S>>От защищает от вызова методов, которые не помечены как const.
·>Как и const-интерфейс. В чём поинт-то?

Внутри этого вашего const-интерфейса кто-то что-то гарантирует?

S>>И да, в это сложно не поверить, после того, как компилятор столько раз бил по рукам.

·>С интерфейсом код такой написать тупо не получится

Да ладно!
Мне вот почему-то не помешало:
interface ConstFirstChunkForNextHandler {
    int remainingBytes();
}

class FirstChunkForNextHandler implements ConstFirstChunkForNextHandler {
    private int remainingBytes = 0;
    public int remainingBytes() {
        --remainingBytes;
        return remainingBytes;
    }
}

public class Main
{
    public static void main(String[] args) {
        ConstFirstChunkForNextHandler chunk = new FirstChunkForNextHandler();
        System.out.printf("first call: %d\n", chunk.remainingBytes());
        System.out.printf("first call: %d\n", chunk.remainingBytes());
    }
}


S>>>>const позволяет бить по рукам за попытки модифицировать объект по константной ссылке или указателю.

S>>·>Только это ни от чего не защищает.
S>>Да что вы говорите? И вам можно верить?
·>Правду. Конечно.

С чего бы? Пока что вы вообще никак не продемонстрировали понимания предмета.

S>>·>Им казалось, что const защищает map от модификации значений ключей, и что благодаря этому инварианты map сломать нельзя. Как оказалось, им таки только казалось.

S>>Так в случае с reference_wrapper для const int там не было того самого const int.
·>Они не знали, ну ладно, будем считать забыли.

Нет, они не обратили внимания в запарке спора.

·>Как и ты, когда предлагал мне константные ссылки передавать в другие треды.


Странно, у меня все работает:
#include <string>
#include <vector>
#include <thread>
#include <iostream>

using namespace std::string_literals;

using vector_of_string = std::vector<std::string>;

[[nodiscard]]
std::thread
launch_thread(const vector_of_string & v, int iterations) {
    return std::thread{ [&v, iterations] {
        std::size_t l{};
        for(int i=0; i < iterations; ++i) {
            for(const auto & s :v) l += s.size();
        }
        std::cout << "iterations: " << iterations << ", l=" << l << std::endl;
    }};
}

int main() {
    const vector_of_string immutable_data{ "Hello"s, "World"s };
    std::vector<std::thread> threads;
    threads.push_back(launch_thread(immutable_data, 1'000));
    threads.push_back(launch_thread(immutable_data, 2'000));
    threads.push_back(launch_thread(immutable_data, 3'000));
    for(auto & t : threads) t.join();
}

Проблема на вашей стороне.

·>Именно. Что и сводит на нет полезность константных объектов.


У вас каша в голове. И проблемы не только с воображением, но и с логикой.
Re[65]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 16:27
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Я отвечал на твой кокнретный вопрос "При программировании на Java... Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Ну я и предложил.

S>На что вам сказали, что этот подход не дает никаких иных гарантий, кроме "мамой клянусь". Так чтож вы так убиваетесь-то, вы так не убьетесь.
Как и подход с const. Они эквивалентны логически, синтаксис только отличается.

S>·>Если опыт был серьёзный, то тогда неясно откуда такое непонимание.

S>Непонимание того, что const-а в Java нет? Вы бы доказали, что такое недопонимание имеет место быть.
Не понимание как можно "обходиться без таких вещей как константные ссылки/указатели".

S>·>Хреново он работает.

S>А иногда вообще не работает. А иногда отлично работает.
Ага. Отлично, от других.

S>>>Какую такую проблему?

S>·>Защиты данных от нежелательных изменений.
S>Ох, ё, i-й раз.
S>
S>const std::vector<std::string> immutable_data{ "Hello"s, "World"s };
S>immutable_data.push_back("!"s); // Да как так-то?!!! Да чтож это деется-то, а?
S>

Ровно то же что и с ConstObj obj = new Obj();obj.change();. Отличие по сути только в отсутствии пробела в "Const Obj".

S>·>Как расшарить-то??! Ты рассказал как передать ссылку (хоть на константный, хоть не константный, что ломает всю идею на корню), либо defensive copy, за которую меня упрекал.

S>Константную ссылку на константный объект. Какую идею это ломает Видимо, это что-то очень личное.
Этого мало. Надо чтобы не было возможности передавать ссылку на неконстантный объект. Иначе это вся затея коту под хвост.

S>·>Если сложно разобраться что делает данный конкретный метод — это либо хреновый яп, либо хреново написанный метод.

S>Вы что, живете в стране розовых пони? Мне вот по работе приходится заглядывать в методы на сотни строк. Ничего хорошего в этом нет, но в объективной реальности это вот прям чуть ли не на каждом шагу.
В таком методе не будет никаких "mutator", "reader" будет:
Qwer data = nmqwert();
zdfkgjq(data);
ouqengtn(data);
qhrign(data);

Вот теперь расскажи где тут что меняется, а где нет, и чем тут помог const.

S>·>Ты так и не рассказал как же _передать_ (копирование это не передача) константный объект куда-то, чтобы он там и оставался гарантированно константным (чтобы туда нельзя было передать неконстантный).

S>Я не утверждал про невозможность передать неконстанный объект по константной ссылке. Вы что-то путаете.
Ты обещал, что передавать константные ссылки другим тредам — безопасно. Нет, это не так.
А вот иммутабельные объекты — действительно безопасно.

S>·>С т.з. системы типов C++ — типы разные, не выдумывай.

S>OK. Но сколько усилий нам нужно, чтобы получить эти разные типы?
В каких попугаях мерить будем?

S>·>Попробуй расскажи о принципиальной разнице "const MyApplicationType" и "ConstMyApplicationType" с практической точки зрения.

S>Это две разных сущности, существование которых нужно оправдать. А потом вспомнить про "не плодите сущности без надобности"
Я написал "const MyApplicationType" и "ConstMyApplicationType".

S>>>В Java у нас был MyApplicationType, затем к нему добавились MyApplicationTypeMutableIface и MyApplicationTypeImmutableIface. Никаких новых сущностей, ага. Шило на мыло, понятненько.

S>·>Зачем?! "MyApplicationType" и "ConstMyApplicationType". Было два, стало два.
S>О да, стало сильно легче.
Я не обещал легче, я говорил ровно столько же. А ты вот лишниего нафантазировал.

S>>>Да вот, хотя бы: https://github.com/Stiffstream/arataga/blob/master/arataga/acl_handler/first_chunk.hpp#L123-L168

S>·>Ну и? Что тут даёт const?
S>Дает указание компилятору на то, что его можно вызывать по константной ссылке, так и по неконстантной.
Мне пофиг на компилятор. Что это даёт юзерам компилятора?

S>·>От тут тупо не нужен.

S>Да что вы говорите! Кто бы мог подумать...
Да. Подумай, тебе может даже понравится.

S> // А потом кто-то с кривыми руками...

S> remaining_bytes--;
Ох, ну господи. Добавь "final" в декларацию remaining_bytes, я забыл при копипасте: final int remaining_bytes;. Вселенная спасена?

S>>>Еще раз: у вас есть объект o, у которого вы вызываете метод getX. Схерали метод getX должен иметь непосредственное отношение к состоянию объекта o?

S>·>Результат метода зависит от состояния объекта.
S>Повторюсь: схерали?
А от чего ещё-то? Для иммутабельного-то типа?

S>·>Методу по логике вещей qwerAsdf либо нужно менять Map, либо не нужно. Если не нужно — он менять не будет.

S>Как это гарантировать средствами языка?
_Если надо_, то создать интерфейс с соответсвующими методами. В интерфейсе ты можешь точно зафиксировать что qwerAsdf может делать, а что не может. Притом не обязательно ограничиваться константностью.

S>·>А это какую проблему решает?

S>Проблему понимания константности в C++.
Очень важная и нужная проблема (нет).

S>·>Если кто-то поменяет сигнатуру метода reader, то в этом месте это тупо всё тихо поломается. Глядя на этот код только — ничего сказать нельзя. Тебе нужно видеть все сигнатуры и верить, что эти сигнатуры не поменяются.

S>Если сигнатуры меняются, то наличие const в нужных местах приводит к ошибкам компиляции.
В приведённном тобой месте — не приводит.

S>·>Я уже показывал аналог тут
Автор: ·
Дата: 13.05.23
, константа константой константу погоняет, а всё тихо сломалось.

S>Так там нет константы. Вы опять не выучили матчасть.
Там то, что предложил rg45 в качестве "решения". И заявил, что это т.к. позволяет "сслаться на константные данные". Нет, не позволяет.

S>>>·>А с многопоточкой так ещё хуже.

S>>>Не обязательно. It depends.
S>·>Конечно. Но совершенно не depends от const. Пользы от const — ноль в данном случае.
S>Ой, ё. А мужики-то и не знают!
Я рад, что ты узнал что-то новое.

S>·>Не подходит const для реализации иммутабельности.

S>У вас, давайте говорить определеннее.
Ок. Начни с того, что объясни создателям D что они ошиблись вводя "immutable" при наличии "const". Ведь по-твоему можно только "const" обойтись.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[66]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 15.05.23 17:06
Оценка:
Здравствуйте, ·, Вы писали:

·>Ровно то же что и с ConstObj obj = new Obj();obj.change();. Отличие по сути только в отсутствии пробела в "Const Obj".


То есть надо для каждого класса отдельно описывать его константного "брата"?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[66]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 15.05.23 17:07
Оценка:
Здравствуйте, ·, Вы писали:

Мне надоело мусолить вашу тупость, поэтому вымараю то, что без мата комментировать уже невозможно.

·>Надо чтобы не было возможности передавать ссылку на неконстантный объект.


Прикиньте, а мне бывают нужны и константные ссылки на неконстантные объекты. И я рад, что в C++ такая возможность есть.

S>>Я не утверждал про невозможность передать неконстанный объект по константной ссылке. Вы что-то путаете.

·>Ты обещал, что передавать константные ссылки другим тредам — безопасно.

Вы уверены, что я это утверждал?

·>Мне пофиг на компилятор.


А мне нет. Компилятор мне помогает.

·>Что это даёт юзерам компилятора?


Строгий компилятор помогает сократить затраты на разработку. Т.е. юзер выигрывает в сроках, качестве и стоимости.

·>Ох, ну господи. Добавь "final" в декларацию remaining_bytes, я забыл при копипасте: final int remaining_bytes;. Вселенная спасена?


Вы рехнулись? Этот элемент должен быть изменяемым.

Ах да, у вас же каша в голове.

S>>Повторюсь: схерали?

·>А от чего ещё-то?

Ответ вопросом на вопрос. Так и запишем. Вы не можете объяснить, у вас просто какой-то шаблон в мозгах отпечатался и за его пределы вы не можете выглянуть.

S>>·>Методу по логике вещей qwerAsdf либо нужно менять Map, либо не нужно. Если не нужно — он менять не будет.

S>>Как это гарантировать средствами языка?
·>_Если надо_, то создать интерфейс с соответсвующими методами.

Т.е. никак. Об этом вам талдычат уже который раз.

S>>·>А это какую проблему решает?

S>>Проблему понимания константности в C++.
·>Очень важная и нужная проблема (нет).

Тем не менее, обсуждается здесь именно она. Если вы не даете себе труда в нее вникнуть, то лучше бы вам вообще завершить этот разговор.

·>Ок. Начни с того, что объясни создателям D что они ошиблись вводя "immutable" при наличии "const". Ведь по-твоему можно только "const" обойтись.


А давайте вы вот это "по-твоему" подтвердите цитатами.

И еще я был бы признателен, если бы вы обратили внимание вот на эти мои слова
Автор: so5team
Дата: 12.05.23
:

Один из самых фундаментальнейших. Правда, в C++ его до ума не довели. А в D слегка переборщили.

Re[71]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 17:30
Оценка:
Здравствуйте, so5team, Вы писали:

S>>>·>Да. А ты веришь что const от чего-то защищает.

S>>>От защищает от вызова методов, которые не помечены как const.
S>·>Как и const-интерфейс. В чём поинт-то?
S>Внутри этого вашего const-интерфейса кто-то что-то гарантирует?
Ок. То что "От защищает от вызова методов, которые не помечены" ты значит согласился. Возражений нет.
А внутри метода защита будет с помощью final.

S>>>И да, в это сложно не поверить, после того, как компилятор столько раз бил по рукам.

S>·>С интерфейсом код такой написать тупо не получится
S>Мне вот почему-то не помешало:
Ну добавь final.

S>Нет, они не обратили внимания в запарке спора.

S>·>Как и ты, когда предлагал мне константные ссылки передавать в другие треды.
S>Странно, у меня все работает:
Потому что ты работающий код написал. Мы говорим о возможности написать неработающий код который пропустит компилятор.

S> const vector_of_string immutable_data{ "Hello"s, "World"s };

Что помешает убрать const здесь? И помодифицировать immutable_data перед join()?

S>Проблема на вашей стороне.

А на вашей стороне потенциальные баги.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[67]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 15.05.23 17:37
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>·>Ровно то же что и с ConstObj obj = new Obj();obj.change();. Отличие по сути только в отсутствии пробела в "Const Obj".


TB>То есть надо для каждого класса отдельно описывать его константного "брата"?


А если объект нельзя менять только в определённых состояниях?
Re[67]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 15.05.23 22:03
Оценка:
Здравствуйте, so5team, Вы писали:

s> Мне надоело мусолить вашу тупость, поэтому вымараю то, что без мата комментировать уже невозможно.

Попробуй включить мозг и всё получится.

s> ·>Надо чтобы не было возможности передавать ссылку на неконстантный объект.

s> Прикиньте, а мне бывают нужны и константные ссылки на неконстантные объекты. И я рад, что в C++ такая возможность есть.
Ого. Ты, похоже, начинаешь что-то подозревать наконец-то. Теперь подумай почему в rust для нормального const понадобился borrow checker.

s> ·>Ты обещал, что передавать константные ссылки другим тредам — безопасно.

s> Вы уверены, что я это утверждал?
Ты утверждал, что константность как-то что-то защищает при передаче данных между тредами и упомянул константные ссылки. И в итоге получилось то, что надо просто создать константный объект, передать ссылку на него другому треду, веря в то, что никто никогда не передаст ничего другое этому треду.
Что, внезапно, эквивалентно в java созданию иммутабельного объекта и передача его по ссылке, без всяких констатностей.
А если использовать иммутабельные типы,то и веры никакой не надо.
Это отвечает на твой начальный вопрос?

s> ·>Что это даёт юзерам компилятора?

s> Строгий компилятор помогает сократить затраты на разработку. Т.е. юзер выигрывает в сроках, качестве и стоимости.
Что конкретно? Ты общими словами не отмазывайся.

s> ·>Ох, ну господи. Добавь "final" в декларацию remaining_bytes, я забыл при копипасте: final int remaining_bytes;. Вселенная спасена?

s> Вы рехнулись? Этот элемент должен быть изменяемым.
Это вы заврались. В приведённом тобой коде он не был изменяемым. Точнее, он там вынужденно изменяемый из-за наличия operator=.

s> S>>Повторюсь: схерали?

s> ·>А от чего ещё-то?
s> Ответ вопросом на вопрос. Так и запишем. Вы не можете объяснить, у вас просто какой-то шаблон в мозгах отпечатался и за его пределы вы не можете выглянуть.
Потому что нет ничего другого в иммутабельном объекте от чего может зависеть результат вызова его метода.

s> Т.е. никак. Об этом вам талдычат уже который раз.

От того, что ты талдычишь фигню много раз, она не перестаёт быть фигнёй.

s> S>>Проблему понимания константности в C++.

s> ·>Очень важная и нужная проблема (нет).
s> Тем не менее, обсуждается здесь именно она.
Вопрос задал ты. Я на него как смог ответил. Тебе ответ не по вкусу, ну твои проблемы.

s> Если вы не даете себе труда в нее вникнуть,

Это твоя личная фантазия.

s> то лучше бы вам вообще завершить этот разговор.



s> ·>Ок. Начни с того, что объясни создателям D что они ошиблись вводя "immutable" при наличии "const". Ведь по-твоему можно только "const" обойтись.

s> А давайте вы вот это "по-твоему" подтвердите цитатами.
Здесь
Автор: so5team
Дата: 15.05.23
:

что иммутабельность можно пытаться обеспечить разными способами. ... можно с помощью средств языка. В C++ таковыми являются const.

Ок. Я ошибся Ты тут утверждал, что только лишь попытаться можно (правда зачем, так и не объяснил, результат же известен, что нихера не выйдет). Согласись, что до тебя наконец-то дошло, что с помощью const нельзя обеспечить иммутабельность и можно разойтись.

s> И еще я был бы признателен, если бы вы обратили внимание вот на эти мои слова
Автор: so5team
Дата: 12.05.23
:

s> Один из самых фундаментальнейших. Правда, в C++ его до ума не довели. А в D слегка переборщили.
Его нельзя довести до ума. В этом и суть. Точнее для этого нужна тяжелая артиллерия в виде, например, borrow checker.
В D добавили const чтобы не отпугнуть таких как ты от языка, который претендовал на улучшенные плюсы. А для всего остального добавили immutable.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[68]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 16.05.23 04:46
Оценка:
Здравствуйте, ·, Вы писали:

s>> Мне надоело мусолить вашу тупость, поэтому вымараю то, что без мата комментировать уже невозможно.

·>Попробуй включить мозг и всё получится.

В вашем случае мозг придется включать психиатрам во время вашего лечения. Ибо откровенные проблемы с логическим мышлением прямо на поверхности:

·>Согласись, что до тебя наконец-то дошло, что с помощью const нельзя обеспечить иммутабельность и можно разойтись.


Есть заявление "нельзя". Есть простейший пример, который демонстрирует обратное:
#include <string>
#include <vector>
#include <thread>
#include <iostream>

using namespace std::string_literals;

using vector_of_string = std::vector<std::string>;

[[nodiscard]]
std::thread
launch_thread(const vector_of_string & v, int iterations) {
    // Здесь компилятор запрещает модифицировать v.
    return std::thread{ [&v, iterations] {
        // Здесь компилятор запрещает модифицировать v.
        std::size_t l{};
        for(int i=0; i < iterations; ++i) {
            for(const auto & s :v) l += s.size();
        }
        std::cout << "iterations: " << iterations << ", l=" << l << std::endl;
    }};
}

int main() {
    const vector_of_string immutable_data{ "Hello"s, "World"s };
    // Здесь компилятор запрещает модифицировать immutable_data.
    std::vector<std::thread> threads;
    threads.push_back(launch_thread(immutable_data, 1'000));
    threads.push_back(launch_thread(immutable_data, 2'000));
    threads.push_back(launch_thread(immutable_data, 3'000));
    for(auto & t : threads) t.join();
}


Итого: тезис "нельзя" опровергнут примером (даже несколькими примерами по ходу обсуждения).

Дальнейшее упрямство поциента должно являться предметом интереса у специалистов-мозгоправов.

PS.

·>Это вы заврались. В приведённом тобой коде он не был изменяемым. Точнее, он там вынужденно изменяемый из-за наличия operator=.


Нет. Просто ваш "эквивалент" вовсе и не эквивалент: это и не value type, и не допускает модификацию значения in place.
Отредактировано 16.05.2023 7:25 so5team . Предыдущая версия .
Re[72]: Когда это наконец станет defined behavior?
От: rg45_from_ban  
Дата: 16.05.23 08:03
Оценка:
Здравствуйте, ·, Вы писали:

·>Не мешает. Но не грозит неизвестными последствиями, как в случае веры в то, что наличие const защищает от изменений (на что, например, напоролись T4r4sB и rg45 тут
Автор: ·
Дата: 13.05.23
, а ведь наверняка у них опыта в плюсах поболее моего).


·>Им казалось, что const защищает map от модификации значений ключей, и что благодаря этому инварианты map сломать нельзя. Как оказалось, им таки только казалось.


·>Они не знали, ну ладно, будем считать забыли. Как и ты, когда предлагал мне константные ссылки передавать в другие треды.


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

Ты вынуждаешь меня нарушать правила форма и отвечать тебе из бана. Я писал тебе письмо с просьбой прекратить писать домыслы от моего имени. Но, то ли письмо мое не дошло, то ли ты его просто проигнорировал. Ничего мне казалось. И как я мог не знать о такой возможности, если я сам же и разбирал выше по коду практичестки тот же случай: http://rsdn.org/forum/cpp/8514772.1
Автор: rg45
Дата: 29.04.23
. И там же я подчеркивал, что константность ссылки не гарантирует неизменности объекта.

По поводу твоего примера
Автор: ·
Дата: 13.05.23
, мне казалось, что я все написал достаточно ясно вот в этих двух сообщениях:

https://rsdn.org/forum/cpp/8527139.1
Автор: rg45
Дата: 13.05.23

https://rsdn.org/forum/cpp/8527147.1
Автор: rg45
Дата: 13.05.23


Но, судя по тому, что ты пишешь потом, ты истолковал их как-то очень по-своему. Попробую написать немного другими словами: ты приводишь случай, который носит все признаки либо очень экзотической ситуации, либо просто дефективного дизайна. И ты этому случаю пытаешься придать статус какой-то всеобщей проблемы. Но это не так. В данном конкретном примере у программиста есть аж целых два способа избежать стрельбы себе в ногу: либо положить в мапу значение, либо объявить объект key изначально константным. Для чего может потребоваться использовать в качестве ключа мапы ссылку на неконстантый объек, я даже придумать сходу не могу, это точно или какая-то экзотика, или просто кривизна.

И в завершение еше раз повторяю мою огромную просьбу: пожалуйста, не нужно ничего здесь писать от моего имени или рассказывать о том, что мне показалось. Дай мне спокойно досидеть свой бан и не вынуждай меня нарушать правила форума. Договорились?
Отредактировано 16.05.2023 8:08 rg45_from_ban . Предыдущая версия . Еще …
Отредактировано 16.05.2023 8:06 rg45_from_ban . Предыдущая версия .
Отредактировано 16.05.2023 8:05 rg45_from_ban . Предыдущая версия .
Re[69]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 08:04
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Согласись, что до тебя наконец-то дошло, что с помощью const нельзя обеспечить иммутабельность и можно разойтись.

s> Есть заявление "нельзя". Есть простейший пример, который демонстрирует обратное:
Я вроде написал что оно работает на вере и даже рассказал как сломать. Небольшое изменение — и взлетит на воздух. В отличие, например, от rust или D с immutable.

Вот, если ты не понял:
s>
// Здесь компилятор разрешает не добавлять const (случайно или по логике вещей) или банально забыть:
s>     vector_of_string immutable_data{ "Hello"s, "World"s };

s>     std::vector<std::thread> threads;
s>     threads.push_back(launch_thread(immutable_data, 1'000));
s>     threads.push_back(launch_thread(immutable_data, 2'000));
s>     threads.push_back(launch_thread(immutable_data, 3'000));

// а потом добавить спецэффектов: 
immutable_data.push_back("ups");

s>     for(auto & t : threads) t.join();
s>

А уж если совсем с козырей зайти, то и с контролем времени жизни будет проблема — достаточно забыть t.join() и оно разлетится. Тут только borrow checker справляется (ну или gc как в java).

s> Итого: тезис "нельзя" опровергнут примером (даже несколькими примерами по ходу обсуждения).



s> Дальнейшее упрямство поциента должно являться предметом интереса у специалистов-мозгоправов.

А тебе бы пустырник для успокоения, да компрессик для охлаждения.

s> ·>Это вы заврались. В приведённом тобой коде он не был изменяемым. Точнее, он там вынужденно изменяемый из-за наличия operator=.

s> Нет. Просто ваш "эквивалент" вовсе и не эквивалент: это и не value type, и не допускает модификацию значения in place.
В java другие подходы для организации кода. Внезапно. И там in-place практически не используется.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 16.05.2023 8:07 · . Предыдущая версия .
Re[67]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 08:21
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> ·>Ровно то же что и с ConstObj obj = new Obj();obj.change();. Отличие по сути только в отсутствии пробела в "Const Obj".

TB> То есть надо для каждого класса отдельно описывать его константного "брата"?
Это плюсовикам кажется, что у каждого класса непременно нужна и важна константность на половине методов.
Интерфейсы пишутся по дизайну приложения, по конкретным бизнес-требованиям кода, а не по константности.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[70]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 16.05.23 08:26
Оценка:
Здравствуйте, ·, Вы писали:

s>> ·>Согласись, что до тебя наконец-то дошло, что с помощью const нельзя обеспечить иммутабельность и можно разойтись.

s>> Есть заявление "нельзя". Есть простейший пример, который демонстрирует обратное:
·>Я вроде написал что оно работает на вере

Вы здесь много откровенной херни написали.

·>и даже рассказал как сломать.


Чтобы сломать нужно избавиться от константности. И, внезапно, это будет разговор на совсем другую тему.

Пока же const в коде присутствует, компилятор бьет по рукам. И это очень хорошо.

Гораздо лучше, чем в Java, Ruby и Python.

·>В отличие, например, от rust или D с immutable.


Вам осталось доказать, что я где-то утверждал о превосходстве C++ над данными языками в этом аспекте.

·>Вот, если ты не понял:




·>// Здесь компилятор разрешает не добавлять const (случайно или по логике вещей) или банально забыть:


Специально для поциентов с проблемами восприятия: Чтобы сломать нужно избавиться от константности. И, внезапно, это будет разговор на совсем другую тему.
Re[73]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 08:51
Оценка:
Здравствуйте, rg45_from_ban, Вы писали:

r> Ты вынуждаешь меня нарушать правила форма и отвечать тебе из бана. Я писал тебе письмо с просьбой прекратить писать домыслы от моего имени. Но, то ли письмо мое не дошло, то ли ты его просто проигнорировал.

Не вижу никаких писем, даже в спам-боксе.

Твоя цитата:
r> программист МОЖЕТ обеспечить реальную константность адресуемых данных.
Я не с этим спорю. Но это заслуга программиста, а не const или проверки компилятора. В этом и есть мой поинт. Программист МОЖЕТ хоть на brainfuck с ассемблерными вставками работающий код, без всяких const.
Иными словами const не является какой-то важной и нужной фичей. Поэтому неудивительно, что другие ЯП как-то без него обходятся.
Я начал обсуждение с попытки ответить на вопрос: "Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". (кстати про любимые so5team константные _объекты_ речи не шло).

r> такое где-то встрется, то, наверное, это следует рассматривать как какую-то вынужденную исключительную меру

Это, как правило, само вылазит в больших долго развивающихся проектах.

r> Для чего может потребоваться использовать в качестве ключа мапы ссылку на неконстантый объек, я даже придумать сходу не могу, это точно или какая-то экзотика, или просто кривизна.

Проблема в том, что нет возможности заставить компилятор иметь ссылку на _только_ константный объект. Там где у тебя используются константные ссылки, туда можно пихать всё что угодно. Следовательно наличие константной ссылки не гарантирует неизменность данных.
Более того, это ведёт к ложному чувству защищённости. Вот тут
Автор: T4r4sB
Дата: 12.05.23
T4r4sB откровенно заявляет, что const защищает ключи в хеш-мапе от изменений. И ты ему поставил плюсик, я это воспринял, что ты имеешь такое же мнение.

r> Дай мне спокойно досидеть свой бан и не вынуждай меня нарушать правила форума. Договорились?

Так это форум, хоть через год отвечай.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[71]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 09:05
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>и даже рассказал как сломать.

s> Чтобы сломать нужно избавиться от константности. И, внезапно, это будет разговор на совсем другую тему.
Константные ссылки таки остались, не знаю что ты подразумеваешь от избавления от константности.
Напомню твой вопрос: "При программировании на Java, Ruby или Python, где подобного понятия константной ссылки нет. Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Объектов тут и не было.

s> Пока же const в коде присутствует, компилятор бьет по рукам. И это очень хорошо.

Так он присутствует на ссылках, но по рукам не бьёт.

s> Гораздо лучше, чем в Java, Ruby и Python.

Ровно так же. Просто будет иммутабельный List и собственно всё. Вместо навешивания константности — навешиваешь неизменяемость. Вот и вся разница.

s> ·>// Здесь компилятор разрешает не добавлять const (случайно или по логике вещей) или банально забыть:



s> Специально для поциентов с проблемами восприятия:

Хамло ты гороховое. Но понимаю, C++ не даёт расслабляться. Тебе надо молоко за вредность требовать.

s>Чтобы сломать нужно избавиться от константности. И, внезапно, это будет разговор на совсем другую тему.

Чтобы избавиться, надо чтобы оно изначально там было. Я же написал, например, константность на объект можно забыть добавить изначально.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[72]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 16.05.23 09:27
Оценка:
Здравствуйте, ·, Вы писали:

·>Константные ссылки таки остались, не знаю что ты подразумеваешь от избавления от константности.


Сперва вы убираете const с объявления immutable_value, а затем пишете "не знаю что ты подразумеваешь от избавления от константности". И после этого хотите, чтобы вас воспринимали психически здоровым человеком?

·>Напомню твой вопрос: "При программировании на Java, Ruby или Python, где подобного понятия константной ссылки нет. Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Объектов тут и не было.


Объекты появились вскоре после этого:

http://rsdn.org/forum/cpp/8526303.1
Автор: ·
Дата: 12.05.23
-- вы заговорили про иммутабельные объекты и речь зашла о каких-либо гарантиях со стороны компилятора.
http://rsdn.org/forum/cpp/8527002.1
Автор: ·
Дата: 13.05.23
-- когда вы привели пример:
std::string oops{ "Hello, World" };
const std::string &hello = oops;

на который вам было сказано, что там нет константных объектов.

И далее речь зашла о наличии толка от константных объектов и что с ними можно делать.

Поскольку разговор длится уже очень долго, то странно аппелировать лишь к его началу, когда был задан исходный вопрос о том, что в Java/Ruby/Python делают не имя константных ссылок/указателей.

s>> Пока же const в коде присутствует, компилятор бьет по рукам. И это очень хорошо.

·>Так он присутствует на ссылках, но по рукам не бьёт.

Он продолжает бить в launch_thread. Что уже немало.

·>Ровно так же.


Для клинических идиотов, разве что.

·>Вместо навешивания константности — навешиваешь неизменяемость. Вот и вся разница.


На колу мочало. Там все гарантии на уровне "мамой клянусь".

s>>Чтобы сломать нужно избавиться от константности. И, внезапно, это будет разговор на совсем другую тему.

·>Чтобы избавиться, надо чтобы оно изначально там было. Я же написал, например, константность на объект можно забыть добавить изначально.

И, внезапно, константности и не будет. И это опять же будет разговор на совсем другую тему.
Отредактировано 16.05.2023 10:05 so5team . Предыдущая версия .
Re[73]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 10:09
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Константные ссылки таки остались, не знаю что ты подразумеваешь от избавления от константности.

s> Сперва вы убираете const с объявления immutable_value,
А что-то запрещает убирать? Или даже — а разве что-то заставляет писать?

s> а затем пишете "знаю что ты подразумеваешь от избавления от константности". И после этого хотите, чтобы вас воспринимали психически здоровым человеком?

Ты прочитай что я написал и не искажай мои слова.

s> ·>Напомню твой вопрос: "При программировании на Java, Ruby или Python, где подобного понятия константной ссылки нет. Как вы предлагаете обходиться без таких вещей как константные ссылки/указатели?". Объектов тут и не было.

s> Объекты появились вскоре после этого:
Потому что ты понял, что сел в лужу с ссылками и указателями, которые вообще никаких полезных гарантий не дают.

s> И далее речь зашла о наличии толка от константных объектов и что с ними можно делать.

Как оказалось — только иметь их внутри метода. И собственно всё. Мой поинт был, что пользы от этого — маловато будет, кроме плюсов такое никуда тащить не стали (ну ладно, D ещё, для обратной совместимости с упёртыми девелоперами), зато иммутабельные объекты — нужны и полезны, и тащатся и используются повсюду. Если для тебя есть великая польза в полумерах в виде const, то пожалуйста. Пользуйся на здоровье, это не меняет ответ на твой изначальный вопрос "как же можно обходиться без" — да очень легко и просто.

s> Поскольку разговор длится уже очень долго, то странно аппелировать лишь к его началу, когда был задан исходный вопрос о том, что в Java/Ruby/Python делают не имя константных ссылок/указателей.


s> s>> Пока же const в коде присутствует, компилятор бьет по рукам. И это очень хорошо.

s> ·>Так он присутствует на ссылках, но по рукам не бьёт.
s> Он продолжает бить в launch_thread. Что уже немало.
Ок, это уже субъективное мнение и приоритеты. Дизайнеры многих более современных ЯП решили, что ооочень мало. И вообще того не стоит того, если учесть усложнение системы типов и различного кода, особенно библиотечного.

s> ·>Вместо навешивания константности — навешиваешь неизменяемость. Вот и вся разница.

s> На колу мочало. Там все гарантии на уровне "мамой клянусь".
Ну да const на объекте — мамой клянусь. В чём твоё возражение-то?

s> И, внезапно, константности и не будет. И это опять же будет разговор на совсем другую тему.

Ты так и не рассказал, как же она там _гарантированно_ появится?
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[74]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 16.05.23 10:21
Оценка:
Здравствуйте, ·, Вы писали:

s>> ·>Константные ссылки таки остались, не знаю что ты подразумеваешь от избавления от константности.

s>> Сперва вы убираете const с объявления immutable_value,
·>А что-то запрещает убирать?

Да. Желание разработчика получить профит от наличия const в языке. Если разработчик умеет это делать.

·>Или даже — а разве что-то заставляет писать?


Да. Опыт и здравый смысл.

s>> а затем пишете "знаю что ты подразумеваешь от избавления от константности". И после этого хотите, чтобы вас воспринимали психически здоровым человеком?

·>Ты прочитай что я написал и не искажай мои слова.

Прочитал и не исказил.

·>Потому что ты понял, что сел в лужу с ссылками и указателями, которые вообще никаких полезных гарантий не дают.


Звиздеть изволите. Ну или покажите хотя бы одно мое утверждение о том, что const ссылки/указатели дают гарантии.

s>> И далее речь зашла о наличии толка от константных объектов и что с ними можно делать.

·>Как оказалось — только иметь их внутри метода.



·>И собственно всё.


Нет. Просто вы не смогли осилить const в C++.

·>Мой поинт был, что пользы от этого — маловато будет


Аминь.

·>кроме плюсов такое никуда тащить не стали (ну ладно, D ещё, для обратной совместимости с упёртыми девелоперами)


ЕМНИП, в D1 вообще const-а не было. const и immutable туда притащили уже в D2, лет через 7-8 после появления D.

·>зато иммутабельные объекты — нужны и полезны, и тащатся и используются повсюду.


Только вот в Java у вас нет никакой помощи от компилятора в их реализации.

·>Пользуйся на здоровье, это не меняет ответ на твой изначальный вопрос "как же можно обходиться без" — да очень легко и просто.


Легко, просто, с ручным добавлением дополнительных сущностей и гарантиями уровня "мамой клянусь". Да, все так.

·>Ок, это уже субъективное мнение и приоритеты. Дизайнеры многих более современных ЯП решили, что ооочень мало.


Как будто я говорил что-то против этого.

·>И вообще того не стоит того, если учесть усложнение системы типов и различного кода, особенно библиотечного.


Для безруких идиотов, не отличающих одно от другого, возможно.

·>Ну да const на объекте — мамой клянусь. В чём твоё возражение-то?


Перечитайте разговор. Здесь было множество примеров того, как компилятор бьет по рукам при наличии const.

Даже если встать на откровенно идиотскую точку зрения (т.е. вашу) о том, что объявление const-объекта -- это уровень "мамой клянусь", то как только const на объекте появился, то далее компилятор начинает следить за работой с этим объектом. И это лучше, чем то, что вы вынуждены делать в Java.

s>> И, внезапно, константности и не будет. И это опять же будет разговор на совсем другую тему.

·>Ты так и не рассказал, как же она там _гарантированно_ появится?

Примеры были показаны. Штудируйте матчасть.
Отредактировано 16.05.2023 10:27 so5team . Предыдущая версия .
Re[75]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 10:49
Оценка:
Здравствуйте, so5team, Вы писали:

s> Да. Желание разработчика получить профит от наличия const в языке. Если разработчик умеет это делать.

s> Да. Опыт и здравый смысл.
Т.е. "мамой клянус". Я знаю. Возражение-то в чём?

s> ·>Потому что ты понял, что сел в лужу с ссылками и указателями, которые вообще никаких полезных гарантий не дают.

s> Звиздеть изволите. Ну или покажите хотя бы одно мое утверждение о том, что const ссылки/указатели дают гарантии.
Ок. То есть нет никаких гарантий, всё мамой клянус. На чём и порешим. Но тогда не требуй каких-то гарантий от других ЯП. А то, видите ли, ява ничего не гарантирует, зато в c++ молитва const позволяет писать правильный код.

s> ·>зато иммутабельные объекты — нужны и полезны, и тащатся и используются повсюду.

s> Только вот в Java у вас нет никакой помощи от компилятора в их реализации.
У тебя опять память подводит. Есть final, record и даже sealed интерфейсы.

s> ·>Пользуйся на здоровье, это не меняет ответ на твой изначальный вопрос "как же можно обходиться без" — да очень легко и просто.

s> Легко, просто, с ручным добавлением не дополнительных сущностей и гарантиями уровня "мамой клянусь". Да, все так.
Как и const. Всё верно.

s> ·>Ну да const на объекте — мамой клянусь. В чём твоё возражение-то?

s> Перечитайте разговор. Здесь было множество примеров того, как компилятор бьет по рукам при наличии const.
И что? У тебя проблемы с логикой. Достаточно одного опровергающего примера и похрен на миллион подтверждающих.

s> Даже если встать на откровенно идиотскую точку зрения (т.е. вашу) о том, что объявление const-объекта -- это уровень "мамой клянусь", то как только const на объекте появился, то далее компилятор начинает следить за работой с этим объектом. И это лучше, чем то, что вы вынуждены делать в Java.

Ровно это же можно сделать с иммутабельными типами. Попробуй в функцию принимающую String запихать CharSequence.

s> ·>Ты так и не рассказал, как же она там _гарантированно_ появится?

s> Примеры были показаны. Штудируйте матчасть.
Ты врёшь опять. В твоём примере показано, что необходимы: "Желание разработчика. Умение это делать. Опыт и здравый смысл". Гарантии не было.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[76]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 16.05.23 11:15
Оценка:
Здравствуйте, ·, Вы писали:

s>> Да. Желание разработчика получить профит от наличия const в языке. Если разработчик умеет это делать.

s>> Да. Опыт и здравый смысл.
·>Т.е. "мамой клянус". Я знаю. Возражение-то в чём?

В том, что в C++ есть возможность написать const для объекта. В Java нет.

s>> ·>Потому что ты понял, что сел в лужу с ссылками и указателями, которые вообще никаких полезных гарантий не дают.

s>> Звиздеть изволите. Ну или покажите хотя бы одно мое утверждение о том, что const ссылки/указатели дают гарантии.
·>Ок.

Ок что? Где цитата, которая подтверждает, что я что-то утверждал или "что сел в лужу с ссылками и указателями"?

·>То есть нет никаких гарантий, всё мамой клянус.


Дяденька, вы реально настолько поехавший?
[[nodiscard]]
std::thread
launch_thread(const vector_of_string & v, int iterations) {
    // Здесь компилятор запрещает модифицировать v.
    return std::thread{ [&v, iterations] {
        // Здесь компилятор запрещает модифицировать v.
        std::size_t l{};
        for(int i=0; i < iterations; ++i) {
            for(const auto & s :v) l += s.size();
        }
        std::cout << "iterations: " << iterations << ", l=" << l << std::endl;
    }};
}

Попробуйте в этом коде просто так модифицировать v.

·>Но тогда не требуй каких-то гарантий от других ЯП.


Схерали?

·>А то, видите ли, ява ничего не гарантирует


Не гарантирует.

·>зато в c++ молитва const позволяет писать правильный код.


Да.

s>> ·>зато иммутабельные объекты — нужны и полезны, и тащатся и используются повсюду.

s>> Только вот в Java у вас нет никакой помощи от компилятора в их реализации.
·>У тебя опять память подводит. Есть final, record и даже sealed интерфейсы.

Ну и как с помощью этого всего сделать из HashMap неизменяемый HashMap? Ну вот был HashMap, требуется сделать так, чтобы его модифицировать нельзя было.

·>Как и const. Всё верно.


Для клинических идиотов повторю еще раз:
void mutate(std::vector<std::string> & v);

const std::vector<std::string> immutable_value{...};
mutate(immutable_value);

Попробуйте заставить компилятор принять у вас такой код.

·>И что? У тебя проблемы с логикой. Достаточно одного опровергающего примера и похрен на миллион подтверждающих.


Хде, хде, блин, этот опровергающий пример? Пока ни одного не было. Были примеры с наличием const-ссылок, но отсутствием const-объектов.

·>Ровно это же можно сделать с иммутабельными типами.


Еще раз для клинических идиотов: дополнительные сущности, которые программист должен делать вручную (хоть и посредством IDE) без какого-либо контроля со стороны компилятора.

s>> ·>Ты так и не рассказал, как же она там _гарантированно_ появится?

s>> Примеры были показаны. Штудируйте матчасть.
·>Ты врёшь опять.

Вы не сможете подтвердить это цитатами.

·>В твоём примере показано


Да, было показано:
int main() {
    const vector_of_string immutable_data{ "Hello"s, "World"s }; // Все, гарантии появились.
Отредактировано 16.05.2023 11:20 so5team . Предыдущая версия .
Re[77]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 16.05.23 16:55
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Т.е. "мамой клянус". Я знаю. Возражение-то в чём?

s> В том, что в C++ есть возможность написать const для объекта. В Java нет.
В java другие подходы для реализации ровно того же.

s> ·>Ок.

s> Ок что? Где цитата, которая подтверждает, что я что-то утверждал или "что сел в лужу с ссылками и указателями"?


s> ·>То есть нет никаких гарантий, всё мамой клянус.

s> Дяденька, вы реально настолько поехавший?
Где уж мне до вас, дяденька.

Thread
launch_thread(Iterable<String> v, int iterations) {
    // Здесь компилятор запрещает модифицировать v.
    return new Thread(()-> {
        // Здесь компилятор запрещает модифицировать v.
        var l = v.stream()
            .limit(iterations)
            .mapToInt(String::length)
            .sum();
        System.out.println("iterations: " + iterations + ", l=" + l);
    });
}

Попробуйте этом коде просто так модифицировать v.

Да, там есть нюанс с Iterator, но это, к сожалению, исторический казус и плохое легаси. collections api в jdk не идеальный. Но это проблема конкретно JDK, а не ЯП.

s> ·>зато в c++ молитва const позволяет писать правильный код.

s> Да.
Ок. Если тебе помогает, можешь молиться в сердце своём. А const в ЯП впендюривать не обязательно.

s> ·>У тебя опять память подводит. Есть final, record и даже sealed интерфейсы.

s> Ну и как с помощью этого всего сделать из HashMap неизменяемый HashMap? Ну вот был HashMap, требуется сделать так, чтобы его модифицировать нельзя было.
Если в типе изначально не предусмотрена константность (не предусмотрены методы с const), то ты нихрена не сделаешь. В HashMap не предусмотрена константность.
Однако, объект HashMap можно сделать неизменяемым, например, с помощью Collections.unmodifiableMap.

s> ·>Как и const. Всё верно.

Для клинических идиотов повторю еще раз:
void mutate(ArrayList<String> v);

Iterable<String> immutable_value = new ArrayList<>(...);
mutate(immutable_value);

Попробуйте заставить компилятор принять у вас такой код.

s> ·>И что? У тебя проблемы с логикой. Достаточно одного опровергающего примера и похрен на миллион подтверждающих.

s> Хде, хде, блин, этот опровергающий пример? Пока ни одного не было. Были примеры с наличием const-ссылок, но отсутствием const-объектов.
Именно. И это никак компилятором не проверяется. Всё на честном слове — не забыл (не смог, т.к. его надо было собрать из кусочков, например) поставить const на объекте — сработает. Не смог — не сработает. И компилятор будет молчать.

s> ·>Ровно это же можно сделать с иммутабельными типами.

s> Еще раз для клинических идиотов: дополнительные сущности, которые программист должен делать вручную (хоть и посредством IDE) без какого-либо контроля со стороны компилятора.
Описывать const-методы программист тоже должен делать вручную. Т.е. решить какие вещи в данном типе могут, а какие не могут быть const.

s> ·>В твоём примере показано

s> Да, было показано:
s>
s> int main() {
s>     const vector_of_string immutable_data{ "Hello"s, "World"s }; // Все, гарантии появились.
s>

Вопрос был: "как же константность объекта там _гарантированно_ появится?" Откуда в данной строчке будет гарантированно стоять модификатор const?
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 16.05.2023 16:56 · . Предыдущая версия .
Re[78]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 17.05.23 05:07
Оценка: +1
Здравствуйте, ·, Вы писали:

s>> ·>Т.е. "мамой клянус". Я знаю. Возражение-то в чём?

s>> В том, что в C++ есть возможность написать const для объекта. В Java нет.
·>В java другие подходы для реализации ровно того же.

Как будто с вами кто-то спорил на тему того такие же они или нет. Мои тезисы касательно Java таковы:

a) требуется вводить новую сущность, интерфейс, который предоставляет read-only доступ к объекту и это не есть хорошо, т.к. это дополнительная (и по сути не нужная) сущность в программе, с которой программисту нужно иметь дело.

Ваши возражения (насколько я их запомнил):

— то, что дополнительная -- не проблема;
— создавать ее дешево за счет помощи IDE.

b) в реализации этой новой сущности со стороны языка нет никакого контроля за тем, выполняются ли там модификации состояния объекта или нет.

Ваши возражения (насколько я их запомнил):

— такого не бывает (у вас по крайней мере);
— есть final и records.

Мой контр-тезис по поводу второго возражения: final бесполезен если поле не value type, в общем, это для частных случаев, а не защита от модификации в общем.

Соответственно, я просто заключаю, что в C++ с const есть больше помощи со стороны собственно языка, чем в Java. Что хорошо и, как по мне, сильно лучше, чем в Java.

При этом я нигде не утверждал, что подход из C++ самый лучший. Напротив, говорил, что в Rust и D пошли еще дальше, и это хорошо, т.к. там смогли учесть опыт C++.

s>> Ок что? Где цитата, которая подтверждает, что я что-то утверждал или "что сел в лужу с ссылками и указателями"?


Таки что с цитатами?

·>Попробуйте этом коде просто так модифицировать v.


Т.е. const в C++ настолько плох, что вы не смогли модифицировать C++ный пример и были вынуждены переводить стрелки на Java.

s>> ·>У тебя опять память подводит. Есть final, record и даже sealed интерфейсы.

s>> Ну и как с помощью этого всего сделать из HashMap неизменяемый HashMap? Ну вот был HashMap, требуется сделать так, чтобы его модифицировать нельзя было.
·>Если в типе изначально не предусмотрена константность (не предусмотрены методы с const), то ты нихрена не сделаешь.

Я все равно смогу объявить экземпляр этого типа как const. Насколько это будет полезно (возможно и будет, т.к. хотя бы указатели на него можно будет использовать) -- это второй вопрос. Но я любой тип могу использовать как const. И это делается средствами языка, а не приседаниями разработчика.

В этом так же принципиальное отличие C++ от Java. В лучшую сторону.

·>В HashMap не предусмотрена константность.


О том и речь.

·>Однако, объект HashMap можно сделать неизменяемым, например, с помощью Collections.unmodifiableMap.


И в compile-time никакой помощи от компилятора не будет.
Но да, она же вам и не нужна, проссыте великодушно.

·>Попробуйте заставить компилятор принять у вас такой код.


Т.е. const в C++ настолько плох, что вы не смогли модифицировать C++ный пример и были вынуждены переводить стрелки на Java.

И это не говоря о том, что вообще-то в C++ vector остается vector-ом с его методами data, at и operator(), тогда как приводя вектор к Iterable в Java вы теряете часть доступных методов.

s>> ·>И что? У тебя проблемы с логикой. Достаточно одного опровергающего примера и похрен на миллион подтверждающих.

s>> Хде, хде, блин, этот опровергающий пример? Пока ни одного не было. Были примеры с наличием const-ссылок, но отсутствием const-объектов.
·>Именно. И это никак компилятором не проверяется. Всё на честном слове — не забыл (не смог, т.к. его надо было собрать из кусочков, например) поставить const на объекте — сработает. Не смог — не сработает. И компилятор будет молчать.

Мне что, нужно в очередной раз повторить, что const&/const* в C++ ничего не говорит о константности исходного объекта?

const&/const* имеют к константности только то отношение, что это единственный легальный способ ссылаться на const-объект. И если нам нужна именно константность, то говорить следует именно о const для объектов, а не о const&/const*.

Примеры когда const для объекта не обеспечивает константность приводить можно и это не сложно (даже без mutable). Кроме того, в C++ с const связаны и другие проблемы (контроль времени жизни, к примеру).

Однако, даже по совокупности, лично я никак не могу согласиться с тем, что от const в C++ мало толку.

·>Описывать const-методы программист тоже должен делать вручную. Т.е. решить какие вещи в данном типе могут, а какие не могут быть const.


Да, это часть работы по проектированию типа.

·> Вопрос был: "как же константность объекта там _гарантированно_ появится?" Откуда в данной строчке будет гарантированно стоять модификатор const?


Для клинических идиотов: не смысла обсуждать вероятность того, что сделает, а чего не сделает пользователь когда речь заходит о возможностях языка. Зато смысл есть обсуждать последствия того, что сделал или не сделал пользователь.

Вот, например, почему-то никто не стремится обсуждать вероятность того, что пользователь ошибется при вычислении значения i перед выполнением операции v[i]. И это правильно, т.к. вероятность совершения ошибки таки есть. Поэтому разумнее сосредоточиться на обсуждении последствий. И в C++ они фатальнее, чем в Java. В этом важное отличие между языками.

Аналогично и с const. Если программист не объявил объект как const, то константности у него нет. Поэтому и нет смысла обсуждать какие-то гарантии со стороны компилятора, ибо их нет.

А вот если программист таки const использовал, вот тогда есть смысл рассуждать о том, что гарантирует компилятор, что не гарантирует и насколько этому const-у можно доверять вообще.

Так что вопрос "как же константность объекта там _гарантированно_ появится?" идет прямиком в /dev/null как в силу своего идиотизма, так и из-за бесполезности.
Re[79]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 17.05.23 12:52
Оценка:
Здравствуйте, so5team, Вы писали:

s>>> В том, что в C++ есть возможность написать const для объекта. В Java нет.

S>·>В java другие подходы для реализации ровно того же.
S>Как будто с вами кто-то спорил на тему того такие же они или нет. Мои тезисы касательно Java таковы:
S>a) требуется вводить новую сущность, интерфейс, который предоставляет read-only доступ к объекту и это не есть хорошо, т.к. это дополнительная (и по сути не нужная) сущность в программе, с которой программисту нужно иметь дело.
Нет _новой_ сущности. Модификатор тоже неявно создаёт новый тип. Вместо неявного типа "const X" делается явный тип "ConstX".

S>Ваши возражения (насколько я их запомнил):

S>- то, что дополнительная -- не проблема;
Нет. Главное возражение — что сущность не дополнительная, а ровно та же, но выраженная другим способом через другие средства ЯП.
Проблема const — это интрузивность. Это усложняет и так непростую систему типов. С другой стороны это частный случай определённого аспекта дизайна.

S>- создавать ее дешево за счет помощи IDE.

Это да. Если набирать всё дело в notepad, то придётся нажать больше кнопок. Тут согласен. Но я давно не набирал код в notepad. Поэтому проблема некритичная совершенно.

S>b) в реализации этой новой сущности со стороны языка нет никакого контроля за тем, выполняются ли там модификации состояния объекта или нет.

S>Ваши возражения (насколько я их запомнил):
S>- такого не бывает (у вас по крайней мере);
Мы рассмотрели твой пример с твоим chunk и там выяснилось, что const даже если бы и был, в java некуда было бы пристроить. Он там просто не нужен.

S>- есть final и records.

Верно. И они относятся к более полезной идее — иммутабельность, а не константность.

S>Мой контр-тезис по поводу второго возражения: final бесполезен если поле не value type, в общем, это для частных случаев, а не защита от модификации в общем.

Ровно настолько же бесполезен, как и const :
struct C
{
    std::string *s = new std::string("hi");
    const std::string &val() const {return *s;}
};

int main()
{
    const C c;
    std::cout << c.val() << std::endl;
    *c.s = "bye";
    std::cout << c.val() << std::endl;
}

В чём разница-то с этим кодом
Автор: so5team
Дата: 12.05.23
, который ты жаве ставил в упрёк? Объект константный, а "модифицировать в общем" можно!

Мой тезис в том, что концепция const и уж тем более реализованная как в плюсах — очень спорной полезности. И в других ЯП уж точно не нужна. У меня есть даже сомнения в её полезности в самих плюсах, но уже не считаю себя экспертом по плюсам, т.к. уж лет 10 на нём не писал.

S>Соответственно, я просто заключаю, что в C++ с const есть больше помощи со стороны собственно языка, чем в Java. Что хорошо и, как по мне, сильно лучше, чем в Java.

Угу. Но он решает несущественную проблему. Эта же проблема с такими же усилиями решается другими, более универсальными средствами.
Конечно, есть небольшое пенальти за универсальность — чуть буковок больше в некоторых случаях (а в реальном проекте разницу и в микроскоп не разглядишь), но и собственно всё.

S>При этом я нигде не утверждал, что подход из C++ самый лучший. Напротив, говорил, что в Rust и D пошли еще дальше, и это хорошо, т.к. там смогли учесть опыт C++.

А некоторые пошли другим путём и выкинули константность вообще. Чем плохо-то?

s>>> Ок что? Где цитата, которая подтверждает, что я что-то утверждал или "что сел в лужу с ссылками и указателями"?

S>Таки что с цитатами?
Не цитаты, а в целом тезисы которые ты выдвигаешь. Константность ссылкок-указателей элементарно заменяется интерфейсом, тут вообще неясно почему ты задал такой вопрос изначально. А константность объектов, на которую ты перешел — не заслуга компилятора, а средство, которое требует усилия и опыт программиста.

S>·>Попробуйте этом коде просто так модифицировать v.

S>Т.е. const в C++ настолько плох, что вы не смогли модифицировать C++ный пример и были вынуждены переводить стрелки на Java.
Он плох в том, что он просто нахрен не нужен как лишняя фича ЯП, т.к. ровно то же делается на уже существующей концепции интерфейсов, которая более мощная и универсальная, делает const ссылкок-указателей тупо ненужным.

s>>> ·>У тебя опять память подводит. Есть final, record и даже sealed интерфейсы.

s>>> Ну и как с помощью этого всего сделать из HashMap неизменяемый HashMap? Ну вот был HashMap, требуется сделать так, чтобы его модифицировать нельзя было.
S>·>Если в типе изначально не предусмотрена константность (не предусмотрены методы с const), то ты нихрена не сделаешь.
S>Я все равно смогу объявить экземпляр этого типа как const. Насколько это будет полезно (возможно и будет, т.к. хотя бы указатели на него можно будет использовать) -- это второй вопрос. Но я любой тип могу использовать как const. И это делается средствами языка, а не приседаниями разработчика.
Для тебя второй вопрос. Для меня — основной. Накой переусложнять ЯП, ради сомнительной околонулевой полезности.

S>В этом так же принципиальное отличие C++ от Java. В лучшую сторону.

Лучшесть — понятие относительное. Java нарочно делали языком простым, как можно проще, но не проще. Если тебе надо кучу фич и концептов, бери какую-нибудь Скалу, на той же платформе.

S>·>В HashMap не предусмотрена константность.

S>О том и речь.
Ну тип такой. В чём возражение-то? В плюсах тоже можно написать тип и не предусмотреть константность. Это как-то повлияет на хорошесть плюсов?

S>·>Однако, объект HashMap можно сделать неизменяемым, например, с помощью Collections.unmodifiableMap.

S>И в compile-time никакой помощи от компилятора не будет.
S>Но да, она же вам и не нужна, проссыте великодушно.
Это особенности реализации конкретного api. Можно найти или реализовать свою библиотеку коллекций, если очень так хочется.
Скажем, в том же C# (который очень похож на java) сделали то что ты хочешь без всяких const, в фреймворке есть набор RO-интерфейсов. Например, List так же реализует IReadOnlyList. А так же есть ImmutableList. Т.е. и иммутабельность есть, и константность, и никакой встроенный в ЯП const нафиг не сдался. Т.е. это вопрос дизайна API и конкретных типов, а не наличия определённой фичи в ЯП.

S>·>Попробуйте заставить компилятор принять у вас такой код.

S>Т.е. const в C++ настолько плох, что вы не смогли модифицировать C++ный пример и были вынуждены переводить стрелки на Java.
Я не понял как ты хотел чтобы я что-то модифицировал и с какой целью. Я привёл как аналгичный трюк const достигается без const, без использования специальных фич ЯП.

S>И это не говоря о том, что вообще-то в C++ vector остается vector-ом с его методами data, at и operator(), тогда как приводя вектор к Iterable в Java вы теряете часть доступных методов.

Это недостаток collections api в jdk, а не Java. Впрочем достать произвольный элемент всё ещё можно через skip/limit. В том же шарпе такой проблемы нет и const нет. Т.е. для реализации того что ты хочешь — const не нужен. Это надо блин просто взять и реализовать.

s>>> Хде, хде, блин, этот опровергающий пример? Пока ни одного не было. Были примеры с наличием const-ссылок, но отсутствием const-объектов.

S>·>Именно. И это никак компилятором не проверяется. Всё на честном слове — не забыл (не смог, т.к. его надо было собрать из кусочков, например) поставить const на объекте — сработает. Не смог — не сработает. И компилятор будет молчать.
S>Мне что, нужно в очередной раз повторить, что const&/const* в C++ ничего не говорит о константности исходного объекта?
Ну да. И это — проблема.

S>const&/const* имеют к константности только то отношение, что это единственный легальный способ ссылаться на const-объект. И если нам нужна именно константность, то говорить следует именно о const для объектов, а не о const&/const*.

Вопрос-то — а нужна ли нам константность объектов в принципе. Я считаю, что иммутабельность нужна, константность — нет. И это делается через List/ImmutableList/IReadOnlyList без каких-либо дополнительных фич в ЯП.

S>Примеры когда const для объекта не обеспечивает константность приводить можно и это не сложно (даже без mutable). Кроме того, в C++ с const связаны и другие проблемы (контроль времени жизни, к примеру).

S>Однако, даже по совокупности, лично я никак не могу согласиться с тем, что от const в C++ мало толку.
Возможно, пусть так. Однако твой вопрос был о толке const в других ЯП.

S>·>Описывать const-методы программист тоже должен делать вручную. Т.е. решить какие вещи в данном типе могут, а какие не могут быть const.

S>Да, это часть работы по проектированию типа.
Именно. По сути ты проектируешь пару типов — const/non-const. Всё то же, никаких дополнительных сущностей, как ты заявил выше.

S>·> Вопрос был: "как же константность объекта там _гарантированно_ появится?" Откуда в данной строчке будет гарантированно стоять модификатор const?

S>Для клинических идиотов: не смысла обсуждать вероятность того, что сделает, а чего не сделает пользователь когда речь заходит о возможностях языка. Зато смысл есть обсуждать последствия того, что сделал или не сделал пользователь.
Вопрос стоял в том как же с помощью const _гарантированно_ защитить данные, которые передаются другим тредам. Как выяснилось — да никак, это лежит на совести и внимательности программиста: создал и передал константный объект — молодец, создал неконстантный объект, но не модифицировал — тоже молодец, а помодицифировал, ну сам виноват. Помощь от компилятора — нулевая. Полный эквивалент List+IReadOnlyList.
Решение только — использовать иммутабельные данные: если другой тред берёт тип ImmutableList, то у тебя 100% гарантия, проверяемая компилятором, что данные не поменяются. Ну или borrow checker.
Т.е. const объект не даёт никакой проверяемой компилятором защиты и в этом случае, только мамойклянус работает.

S>Вот, например, почему-то никто не стремится обсуждать вероятность того, что пользователь ошибется при вычислении значения i перед выполнением операции v[i]. И это правильно, т.к. вероятность совершения ошибки таки есть. Поэтому разумнее сосредоточиться на обсуждении последствий. И в C++ они фатальнее, чем в Java. В этом важное отличие между языками.

А мы не о вероятностях. А о том, что именно даёт конкретная фича ЯП. Пока выяснилось, что константный объект даёт лишь локальную защиту локальной переменной внутри метода. И собственно всё. Что можно сделать, например, вот так:
IReadOnlyList myConstList = new List(...);


S>Аналогично и с const. Если программист не объявил объект как const, то константности у него нет. Поэтому и нет смысла обсуждать какие-то гарантии со стороны компилятора, ибо их нет.

Моё мнение — практической пользы — маловато будет. Пусть это останется вкусовыми предпочтениями.

S>А вот если программист таки const использовал, вот тогда есть смысл рассуждать о том, что гарантирует компилятор, что не гарантирует и насколько этому const-у можно доверять вообще.

В чём разница-то с правильным выбором типов List/ImmutableList/IReadOnlyList?

S>Так что вопрос "как же константность объекта там _гарантированно_ появится?" идет прямиком в /dev/null как в силу своего идиотизма, так и из-за бесполезности.

Ну вот с иммутабельностью этот вопрос почему-то даже не появляется, внезапно. Иммутабельность — полезный концепт, т.к. действительно даёт полезные гарантии.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 17.05.2023 12:53 · . Предыдущая версия .
Re[80]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 17.05.23 15:09
Оценка:
Здравствуйте, ·, Вы писали:

·>Ровно настолько же бесполезен, как и const :

·>
·>struct C
·>{
·>    std::string *s = new std::string("hi");
·>    const std::string &val() const {return *s;}
·>};

·>int main()
·>{
·>    const C c;
·>    std::cout << c.val() << std::endl;
·>    *c.s = "bye";
·>    std::cout << c.val() << std::endl;
·>}
·>

·>В чём разница-то с этим кодом
Автор: so5team
Дата: 12.05.23
, который ты жаве ставил в упрёк? Объект константный, а "модифицировать в общем" можно!




Да ознакомьтесь вы уже наконец с матчастью! Вам от незнания константы мерещатся там, где их нет, что приводит к дурацким утверждениям с вашей стороны, комментировать которые цензурно уже просто невозможно.
Re[81]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 17.05.23 15:26
Оценка:
Здравствуйте, so5team, Вы писали:

S>Да ознакомьтесь вы уже наконец с матчастью! Вам от незнания константы мерещатся там, где их нет, что приводит к дурацким утверждениям с вашей стороны, комментировать которые цензурно уже просто невозможно.

Вы в защиту плюсового const приводите странный код, который показывает незнание матчасти других ЯП. Когда я перевожу идентичный код на разных ЯП, у вас подгорает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[82]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 17.05.23 16:14
Оценка:
Здравствуйте, ·, Вы писали:

S>>Да ознакомьтесь вы уже наконец с матчастью! Вам от незнания константы мерещатся там, где их нет, что приводит к дурацким утверждениям с вашей стороны, комментировать которые цензурно уже просто невозможно.

·>Вы в защиту плюсового const приводите странный код, который показывает незнание матчасти других ЯП.

Я здесь привел, помнится, всего один пример кода на Java, к которому претензий не было.

Вы же мало того, что демонстрируете незнание C++ о котором пытаетесь рассуждать, так еще и не способны прочитать то, что вам пишут: вы увидели константность там, где ее нет.

Все, дальше можно не продолжать, ибо из неверных предпосылок следуют и неверные выводы.
Re[83]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 17.05.23 16:30
Оценка:
Здравствуйте, so5team, Вы писали:

S>·>Вы в защиту плюсового const приводите странный код, который показывает незнание матчасти других ЯП.

S>Я здесь привел, помнится, всего один пример кода на Java, к которому претензий не было.
Не понял почему к коду на Java у меня должны были быть претензии. Претензии у меня к const. То что вы не понимаете какой код на других ЯП без const соответствует какому плюсововому коду с const — это ваше незнание матчасти других ЯП, а не моё незнание плюсов.

Вы даже не понимаете разницу между иммутабельностью и константностью и собирались первое выражать через второе — пробел знания и теоретической матчасти.

S>Вы же мало того, что демонстрируете незнание C++ о котором пытаетесь рассуждать, так еще и не способны прочитать то, что вам пишут: вы увидели константность там, где ее нет.

Я увидел то, что вы показали и просто перевёл с языка на язык.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[84]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 17.05.23 16:54
Оценка:
Здравствуйте, ·, Вы писали:

·>Вы даже не понимаете разницу между иммутабельностью и константностью и собирались первое выражать через второе — пробел знания


И это говорит поциент, который не может объяснить схерали o.getX() должен относиться с состоянию объекта o...

> теоретической матчасти.


Какое прекрасное словосочетание. Интересно, а давно "мат" в "матчасти" стало означать что-то отличное от "материальной"?
Re[85]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 18.05.23 08:14
Оценка:
Здравствуйте, so5team, Вы писали:

s> ·>Вы даже не понимаете разницу между иммутабельностью и константностью и собирались первое выражать через второе — пробел знания

s> И это говорит поциент, который не может объяснить схерали o.getX() должен относиться с состоянию объекта o...
Я объяснил, ты не понял, потому что проблемы в:
s> > теоретической матчасти.
А так как никаких вопросов/комментарием больше не последовало, я сделал вывод, что желания узнать у тебя и нет.

s> Какое прекрасное словосочетание. Интересно, а давно "мат" в "матчасти" стало означать что-то отличное от "материальной"?

У тебя ещё и по матчасти русского языка пробелы. Раз тебе так интересно, отвечу, хоть и оффтоп. Оно стало означать немного другое с тех пор, как "учи матчасть" перешло из армейской терминологии в устойчивое словосочетание (афаир благодаря какому-то фильму) и интернет-жаргон. Некий аналог английского RTFM.
И "матчасть" тут означает "базовые, элементарные знания". Т.е. "теоретическая матчасть" буквально означает "базовые знания теории".
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[86]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 18.05.23 08:50
Оценка:
Здравствуйте, ·, Вы писали:

·>Я объяснил


Нет. Хинт: даже если объект иммутабельный, ничто не обязывает его getX возвращать хоть что-то связанное с его состоянием.

·>А так как никаких вопросов/комментарием больше не последовало


Нуздрасте, я вам повторял вопрос пока была надежда, что вы хоть что-то ответите.

·>Некий аналог английского RTFM.


RTFM -- это про изучение теории?
Это про изучение инструкций к инструменту, т.е. про изучение инструмента, т.е. в точности как "учи матчасть".
Re[51]: Шаблонные "виртуальные" функции?
От: B0FEE664  
Дата: 22.05.23 14:38
Оценка:
Здравствуйте, so5team, Вы писали:

S>Хуже

S>https://habr.com/ru/articles/722668/
S>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html
S>
template <typename T>
S>class optional {
S>  // ...
S>  template <typename Self>
S>  constexpr auto operator->(this Self&& self) {
S>    return addressof(self.m_value);
S>  }
S>  // ...
S>};
S>


Правильно ли я понимаю, что следующий код будет валидным и по сути это будут эмуляция шаблонных виртуальных функций?:

struct B
{
    template<class T> void vfun(T t) { std::cout << t << '\n'; }
    template <typename Self, class T> void f1(this Self&& self, T t) { self.vfun(t); }
};

struct D: B 
{
    template<class T> void vfun(T t) { std::cout << "D:t=" << t << '\n'; }
};

struct C: B 
{
    template<class T> void vfun(T t) { std::cout << "C:t=" << t << '\n'; }
};

int main()
{
    D d{};
    C c{};
    B* pb = &d;
    pb->f1(1);      // output D:t=1 ?
    pb = &c;
    pb->f1("asdf"); // output C:t=asdf ?
    return 0;
}
И каждый день — без права на ошибку...
Re[52]: Шаблонные "виртуальные" функции?
От: so5team https://stiffstream.com
Дата: 22.05.23 15:49
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Правильно ли я понимаю, что следующий код будет валидным и по сути это будут эмуляция шаблонных виртуальных функций?:


Попробовал с VC++ 19.35.32217.1 и получил вот такой результат:
1
asdf

Т.е., нет, шаблонные методы виртуальными не стали. Что, имхо, ожидаемо.

Пробовал на godbolt с trunk-версиями GCC и Clang, но они, как я понял, еще deducing this не поддерживают
(либо я не смог правильные ключики им передать, хотя -std=c++23 указывал).
Re[53]: Шаблонные "виртуальные" функции?
От: B0FEE664  
Дата: 23.05.23 09:47
Оценка:
Здравствуйте, so5team, Вы писали:

BFE>>Правильно ли я понимаю, что следующий код будет валидным и по сути это будут эмуляция шаблонных виртуальных функций?:

S>Попробовал с VC++ 19.35.32217.1 и получил вот такой результат:
S>
S>1
S>asdf
S>

Не, ну так не интересно! При вызове в шаблон подставляется тип переменной, а не тип объекта.

S>Т.е., нет, шаблонные методы виртуальными не стали. Что, имхо, ожидаемо.

Ну да... Ничего по настоящему нового не добавляют.
И каждый день — без права на ошибку...
Re[54]: Шаблонные "виртуальные" функции?
От: so5team https://stiffstream.com
Дата: 23.05.23 09:59
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>При вызове в шаблон подставляется тип переменной, а не тип объекта.


Так там от шаблона только синтаксис, а (как по мне) шаблоном это назвать сложно.
Re[46]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 23.05.23 10:02
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Более того раз это очевидно это может делать компилятор.

А если это не очевидно — то тогда как?
И каждый день — без права на ошибку...
Re[47]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 10:20
Оценка:
Здравствуйте, B0FEE664, Вы писали:

_>>Более того раз это очевидно это может делать компилятор.

BFE>А если это не очевидно — то тогда как?

Как обычно: отделяются котлеты от мух. Описание данных, представление, ограничения, алгоритм, порядок выполнения и инварианты должны описываться отдельно, а не смешиваться в кучу.
Надо описывать так что бы было удобно писать и читать, а компилятору было очевидно какие преобразования допустимы, а не строить домыслы на ложных предпосылках. И не вводить всякие pointer provenance и другие не чуждые понятия.
Более того я бы ввел помимо компиляции еще и стадию синтеза кода, вместо этих ваших метапрограммирований. Что бы можно было явно итерационно преобразовывать код.
Короче C++ для этих целей не подходит, т.к. он развивается в сторону усложнения, не давая ничего нового даже немного вредя.
Re[48]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 23.05.23 10:58
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Короче C++ для этих целей не подходит, т.к. он развивается в сторону усложнения, не давая ничего нового даже немного вредя.


что взамен?
Re[49]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 11:05
Оценка:
Здравствуйте, night beast, Вы писали:

_>>Короче C++ для этих целей не подходит, т.к. он развивается в сторону усложнения, не давая ничего нового даже немного вредя.


NB>что взамен?

Возврат к истокам, надстройки над платформо-независимым ассемблером.
Re[50]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 23.05.23 11:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

NB>>что взамен?

_>Возврат к истокам, надстройки над платформо-независимым ассемблером.

названия?
не слишком низкоуровнево/многословно?
Re[51]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 11:15
Оценка:
Здравствуйте, night beast, Вы писали:

NB>названия?

Какие вам нужны названия?
NB>не слишком низкоуровнево/многословно?
Уровней может быть много. С чего вы взяли что будет многословно?
И да лучше пуcть будут длинные, но понятные, конструкции как vhdl чтобы можно было спокойно найти их поиском чем то что делают в swift, превращая его в инопланетянский язык.
Re[52]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 23.05.23 11:20
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

NB>>названия?

_>Какие вам нужны названия?

готовые реализации. что гуглить.

NB>>не слишком низкоуровнево/многословно?

_>Уровней может быть много. С чего вы взяли что будет многословно?

пока не совсем понятно, как это будет выглядеть на практике.
а так в целом я тоже за все хорошее, против всего плохого.
Re[53]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 12:56
Оценка:
Здравствуйте, night beast, Вы писали:

NB>готовые реализации. что гуглить.

Отделение алгоритма от порядка исполнения: https://people.csail.mit.edu/jrk/halide12/halide12.pdf
Платформо-независимых ассемблеров много: LLVM IR, JVM, IL, C, JS, WebAssembly ...
Отделением данных от представления все занимаются постоянно особенно при передачи данных по сети или при попытках по максимуму использовать кэш.
Синтезом кода занимаются jit, а декларативные языки типа sql строят план выполнения.

NB>пока не совсем понятно, как это будет выглядеть на практике.

Если вы хотите узнать как это будет на практике практикуйте. Пока синтез кода встраивают в ide и то для языков попроще чем c++. Следующий шаг это copilot, но это путь в сторону потери контроля над происходящим. Языках типа CSharp java есть синтез кода, но он не удобен для анализа и требует много приседаний.
NB>а так в целом я тоже за все хорошее, против всего плохого.
Так кто вам сказал что есть готовое. Что бы оно появилось надо что бы умерло множество неудачных прототипов.
Я лично экспериментирую с+lua не сказать что прям что-то грандиозное, но прикольно (некоторые задачи решаются очень элегантно).
Re[54]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 23.05.23 13:19
Оценка:
Здравствуйте, kov_serg, Вы писали:

NB>>готовые реализации. что гуглить.

_>Отделение алгоритма от порядка исполнения: https://people.csail.mit.edu/jrk/halide12/halide12.pdf
_>Платформо-независимых ассемблеров много: LLVM IR, JVM, IL, C, JS, WebAssembly ...
_>Отделением данных от представления все занимаются постоянно особенно при передачи данных по сети или при попытках по максимуму использовать кэш.
_>Синтезом кода занимаются jit, а декларативные языки типа sql строят план выполнения.

иными словами, основная мысль, "выкиньте c++ и используйте dsl"?
мысль не новая, но пока какого-то массированного применения дсл для решения общих задач почему-то не наблюдается

NB>>пока не совсем понятно, как это будет выглядеть на практике.

_>Если вы хотите узнать как это будет на практике практикуйте. Пока синтез кода встраивают в ide и то для языков попроще чем c++. Следующий шаг это copilot, но это путь в сторону потери контроля над происходящим. Языках типа CSharp java есть синтез кода, но он не удобен для анализа и требует много приседаний.

это сразу в топку.

NB>>а так в целом я тоже за все хорошее, против всего плохого.

_>Так кто вам сказал что есть готовое. Что бы оно появилось надо что бы умерло множество неудачных прототипов.
_>Я лично экспериментирую с+lua не сказать что прям что-то грандиозное, но прикольно (некоторые задачи решаются очень элегантно).

не совсем понял, это написано "си и луа", или "экспериментирую с" +lua
если первое то тоже довольно старая комбинация, но на замену c++ никак не тянет
Re[55]: Шаблонные "виртуальные" функции?
От: B0FEE664  
Дата: 23.05.23 14:05
Оценка:
Здравствуйте, so5team, Вы писали:

BFE>>При вызове в шаблон подставляется тип переменной, а не тип объекта.


S>Так там от шаблона только синтаксис, а (как по мне) шаблоном это назвать сложно.

Не, согласно пропазлу, это должен быть именно шаблон:
struct B
{
    template<class T> void vfun(T t) { std::cout << t << '\n'; }
    template <typename Self, class T> void f1(this Self&& self, T t) { self.vfun(t); }
};

struct D: B 
{
    template<class T> void vfun(T t) { std::cout << "D:t=" << t << '\n'; }
};

struct C: B 
{
    template<class T> void vfun(T t) { std::cout << "C:t=" << t << '\n'; }
};

int main()
{
    D d{};
    C c{};
    B* pb = &d;
    d.f1(1);        // обязан вывести D:t=1 
    pb->f1(1);      // output: 1 :(
    pb = &c;
    pb->f1("asdf"); // output: asdf  :(
    c.f1("asdf");   // обязан вывести C:t=asdf
    return 0;
}

я пока проверить не могу.

К тому же согласно пропазлу синтаксис не обязан быть шаблонным:

struct X {
  // explicit object has type X&
  void foo(this X&);

  // explicit object has type X const&
  void foo(this X const&);

  // explicit object has type X&&
  void bar(this X&&);
};

И каждый день — без права на ошибку...
Re[56]: Шаблонные "виртуальные" функции?
От: so5team https://stiffstream.com
Дата: 23.05.23 14:53
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Не, согласно пропазлу, это должен быть именно шаблон:

BFE>
BFE>struct B
BFE>{
BFE>    template<class T> void vfun(T t) { std::cout << t << '\n'; }
BFE>    template <typename Self, class T> void f1(this Self&& self, T t) { self.vfun(t); }
BFE>};

BFE>struct D: B 
BFE>{
BFE>    template<class T> void vfun(T t) { std::cout << "D:t=" << t << '\n'; }
BFE>};

BFE>struct C: B 
BFE>{
BFE>    template<class T> void vfun(T t) { std::cout << "C:t=" << t << '\n'; }
BFE>};

BFE>int main()
BFE>{
BFE>    D d{};
BFE>    C c{};
BFE>    B* pb = &d;
BFE>    d.f1(1);        // обязан вывести D:t=1 
    pb->>f1(1);      // output: 1 :(
BFE>    pb = &c;
    pb->>f1("asdf"); // output: asdf  :(
BFE>    c.f1("asdf");   // обязан вывести C:t=asdf
BFE>    return 0;
BFE>}
BFE>

BFE>я пока проверить не могу.

VC++ версия 19.36.32532 (сегодня обновил VS2022):
D:t=1
1
asdf
C:t=asdf
Re[55]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 15:15
Оценка:
Здравствуйте, night beast, Вы писали:

NB>иными словами, основная мысль, "выкиньте c++ и используйте dsl"?

Вы давно писали свою реализацию C++? А DSL?
NB>мысль не новая, но пока какого-то массированного применения дсл для решения общих задач почему-то не наблюдается
Нет мысль не в этом. Мысль в том что в рамках c++ что-то новое не появится (кроме более затейлевых UB).

NB>не совсем понял, это написано "си и луа", или "экспериментирую с" +lua

NB>если первое то тоже довольно старая комбинация, но на замену c++ никак не тянет
Я где-то написал что это замена? Я к тому что эта связка позволяет её применять к любым задачам довольно не ожиданными способами. При этом весь набор инструментов максимально ни от чего не зависит и ни чем не ограничивает поле для экспериментов.
Re[56]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 23.05.23 18:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

NB>>иными словами, основная мысль, "выкиньте c++ и используйте dsl"?

_>Вы давно писали свою реализацию C++? А DSL?

не писал. а надо?

NB>>мысль не новая, но пока какого-то массированного применения дсл для решения общих задач почему-то не наблюдается

_>Нет мысль не в этом. Мысль в том что в рамках c++ что-то новое не появится (кроме более затейлевых UB).

а, понятно
мне просто показалось что предлагается что-то более конструктивное
Re[57]: Когда это наконец станет defined behavior?
От: kov_serg Россия  
Дата: 23.05.23 19:26
Оценка:
Здравствуйте, night beast, Вы писали:

_>>Вы давно писали свою реализацию C++? А DSL?

NB>не писал. а надо?
У всех разные интересы. Если вам удобнее пользоваться готовым нет проблем.

NB>мне просто показалось что предлагается что-то более конструктивное

Ничего нового я не предлагаю, просто отделить разные понятия что бы было проще ими оперировать и структурировать их. А не смешивать всё в кучу, делая оптимизации на основании заведомо не верных рассуждений. И не вводить наркоманские понятия не связанные с реальностью для оправдания подобных оптимизаций.
Re[58]: Когда это наконец станет defined behavior?
От: night beast СССР  
Дата: 24.05.23 06:01
Оценка:
Здравствуйте, kov_serg, Вы писали:

NB>>мне просто показалось что предлагается что-то более конструктивное

_>Ничего нового я не предлагаю, просто отделить разные понятия что бы было проще ими оперировать и структурировать их. А не смешивать всё в кучу, делая оптимизации на основании заведомо не верных рассуждений. И не вводить наркоманские понятия не связанные с реальностью для оправдания подобных оптимизаций.

дык я не возражаю
просто покажи где это уже сделано и работает
Re[32]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 04.08.23 19:00
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Почему функциональность std::start_lifetime_as<T> и std::launder нельзя было бы повесить на reinterpret_cast<T> ?


reinterpret_cast обычно обслуживает уже имеющийся живой объект.
Если не брать приведение целочисленных типов по-значению, он приводит в других случаях указатели и ссылки.
Причём, требуется, чтобы было приведение к правильному типу, иначе UB.
Одновременно с этим оно означает, что экземпляр типа был уже создан ранее и его жизненный цикл "кем-то" отслеживается.
Re[80]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 16.08.23 12:04
Оценка:
Здравствуйте, ·, Вы писали:

S>>- есть final и records.

·>Верно. И они относятся к более полезной идее — иммутабельность, а не константность.

Дык, мало того, что через константность в С++ легко получить иммутабельность (если требуется именно она), но еще эта иммутабельность может начинаться с некоторой нужной точки в коде.
И это натуральная киллер-фича! ))

Например:
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); // мутабельность
    ...
    return result;
}

const std::map<int, int> someDictionary = buildMap(); // сохранили в иммутабельный объект


В шарпе для такого сценария есть отдельно иммутабельный аналог map, и отдельно мутабельный builder для него.
В С++ не потребовалось создавать две сущности.

Этот сценарий может возникнуть не только вокруг иммутабельного map, где в шарпе постелили соломку, а вообще везде.

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

Остальные сценарии, когда мутабельный объект подаётся по константной ссылке — это просто удобные гарантии, т.к. после вызова метода с таким аргументом ты можешь в коде рассуждать о том, что целевой объект в результате вызова некоей ф-ии с им-аргументом, не изменился.
Отредактировано 17.08.2023 22:29 vdimas . Предыдущая версия . Еще …
Отредактировано 17.08.2023 22:27 vdimas . Предыдущая версия .
Отредактировано 17.08.2023 22:27 vdimas . Предыдущая версия .
Re[81]: Когда это наконец станет defined behavior?
От: σ  
Дата: 16.08.23 17:08
Оценка: +1 -1
V>Например:
V>
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); // мутабельность
}

const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект

Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект. Он будет константным?
Отредактировано 21.08.2023 20:00 σ . Предыдущая версия .
Re[82]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 17.08.23 22:26
Оценка:
Здравствуйте, σ, Вы писали:

σ>Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект.


Ничего особенного.
Результат начинает свой лайфтайм после возврата из хелпера-инициализатора.
Re[83]: Когда это наконец станет defined behavior?
От: σ  
Дата: 17.08.23 22:36
Оценка: +1 -1 :)
σ>>Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект.

V>Ничего особенного.




V>Результат начинает свой лайфтайм после возврата из хелпера-инициализатора.


Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.
Re[84]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 17.08.23 22:47
Оценка:
Здравствуйте, σ, Вы писали:

σ>Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.


Не понял проблемы. Да, адрес у объектов один и тот же, но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.
А вот определить константность объекта в С++ невозможно.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[85]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 07:53
Оценка: +1
σ>>Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.

TB>Не понял проблемы. Да, адрес у объектов один и тот же


У объектов? При NRVO это один объект.

TB>но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.


Что значит «считается»?

TB>А вот определить константность объекта в С++ невозможно.


NRVO поймать-то можно.
Re[86]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 18.08.23 08:11
Оценка: +1
Здравствуйте, σ, Вы писали:

σ>>>Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.


TB>>Не понял проблемы. Да, адрес у объектов один и тот же


σ>У объектов? При NRVO это один объект.


TB>>но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.


σ>Что значит «считается»?


Не очень понятна суть вопросов. В С++ даже у константных объектов есть период времени, когда они константами не считаются:
#include <iostream>

class demo {
public:
    demo() {
        f();
    }

    void f() { std::cout << "I'm not const!" << std::endl; }
    void f() const { std::cout << "I'm const..." << std::endl; }
};

int main() {
    const demo d; // d.f() will be called in the constructor.
    d.f();
}

цинк: https://wandbox.org/permlink/ssqBdbzjjTmb9YoI
Re[84]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 08:13
Оценка:
Здравствуйте, σ, Вы писали:

V>>Результат начинает свой лайфтайм после возврата из хелпера-инициализатора.

σ>Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.

Забавные рассуждения, однако. ))
(у меня там были описки, исправил исходный пример http://www.rsdn.org/forum/cpp/8581544.1)

Переменная result внутри метода имеет свой лайфтайм, не связанный с оным у переменной someDictionary.
Что касается оптимизации возвращаемого значения — это низкоуровневая механика компилятора, ничего не меняющая в семантике исходного кода (если конструктор/деструктор без побочных эффектов).

На проблемы тут можно нарваться только в динамической фазе инициализации глобальных переменных, если переменная someDictionary глобальная и кто-то её юзает до инициализации или умудрился создать в коде динамической инициализации еще один поток и оттуда юзает эту переменную одновременно с наполнением её данными из основного потока.
(после инициализации иммутабельного someDictionary к нему безопасно обращаться из разных потоков без блокировки)

Главное то, что упомянутые бока могут возникнуть даже для классического полностью иммутабельного объекта, инициализирующего все свои поля в конструкторе, т.е. указанный трюк не добавляет никаких новых эффектов к ошибкам, связанным с использованием глобальных неинициализированных переменных.
Re[86]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 08:17
Оценка:
Здравствуйте, σ, Вы писали:

TB>>Не понял проблемы. Да, адрес у объектов один и тот же

σ>У объектов? При NRVO это один объект.

Дудки! ))
Это одна область памяти, в которой по очереди живут два объекта.

А что для трансформации первого объекта во второй не потребовалось никаких телодвижений — не ваше дело, как грится, тут компилятору виднее. ))


TB>>но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.

σ>Что значит «считается»?

Есть такое слово "семантика".


TB>>А вот определить константность объекта в С++ невозможно.

σ>NRVO поймать-то можно.

Но проблем там никаких (при условии, повторюсь, отсутствия побочных эффектов в конструкторе и деструкторе).
Re[81]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 18.08.23 08:34
Оценка:
Здравствуйте, vdimas, Вы писали:


V>В шарпе для такого сценария есть отдельно иммутабельный аналог map, и отдельно мутабельный builder для него.

V>В С++ не потребовалось создавать две сущности.
Именно, то же самое на шарпах делается с помощью интерфейса. А две сущности в C++ тоже есть, просто неявно. Вместо явного интерфейса делается пара const- и просто-методов. Константные объекты появляются не магически, а в определениях соответствующих полей и методов.

V>Этот сценарий может возникнуть не только вокруг иммутабельного map, где в шарпе постелили соломку, а вообще везде.

И там и там надо вводить два типа. Ведь T и const T это тоже разные типы.

V>Собсно, только об этом и говорится в обсуждении (многократно по кругу) — что практически любой мутабельный тип можно использовать в т.ч. в иммутабельных сценариях.

"Практически" в том смысле если для типа правильно спроектирован const подтип. Ровно та же петрушка, что и с интерфейсом.

V>Остальные сценарии, когда мутабельный объект подаётся по константной ссылке — это просто удобные гарантии, т.к. после вызова метода с таким аргументом ты можешь в коде рассуждать о том, что целевой объект в результате вызова некоей ф-ии с им-аргументом, не изменился.

Аналог final.

Суть моего тезиса в том, что семантика const в других ЯП выражается тоже, просто через другие механизмы языка.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[52]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 08:36
Оценка:
Здравствуйте, ·, Вы писали:

TB>> ·>Не понял, ты же в мапу ключ кладёшь снаружи. Или мапа копию делает?

TB>> Копию, конечно.
·>А если указатель?

Тогда ключом является адрес. ))


TB>> ·>Скажем, ключом в мапе может быть массив из миллиона элементов... Дальше продолжать?

TB>> Мув-копию.
·>А если массив является ключом в двух разных мапах?

Встроенный массив не имеет операции сравнения, поэтому не может быть ключом.
Речь может идти о некоем типе-обертке над массивом, в котором ты уже сам разбираешь с принципом владения — static-immutable, unique или shared.


·>К сожалению нет. Класс ключа может меняться, добавляться новые поля, например.


Ты намекаешь на отсутствие автоматического распространения константности по указателям и ссылкам?
Есть такое, так же как есть простая возможность распростанять константность и по указателям/ссылкам.
template<typename T>
class Pointer {
    T * ptr_;

public:
    Pointer(T * ptr = nullptr) : ptr_(ptr) {}

    T * operator->() { return ptr_; }

    const T * operator->() const { return ptr_; }
};


TB>> а вот итерация по мапе делается регулярно и там проследить за кривыми руками кодера сложнее.

·>Короче, может и есть какие-то средства, работающие в каких-то сценариях, никакой гарантии нет.

Гарантии создаёт программист согласно требуемой семантике, разумеется.
Разумеется, и в джаве и в плюсах можно обеспечить все требуемые гарантии.

Здесь сравнивается цена телодвижений в различных сценариях. ))
Абсолютно все подходы джавы по обеспечению гарантий иммутабельности или константности в плюсах есть, что уже не может дать джаве никакого преимущества в этом вопросе. ))
Но сверху этого в плюсах есть в разы более выразительные механизмы, позволяющие не писать лишний код (не засорять им бинарник).
Re[57]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 08:45
Оценка:
Здравствуйте, ·, Вы писали:

·>
·>std::map<std::reference_wrapper<const int>, std::string> map;
·>int key = 42;
·>map[key]= "hi";
·>key++; //упс! Мапа сломана.
·>


reference_wrapper хранит ссылку как значение, т.е. придаёт ссылке св-ва указателя.
Соотв, когда будешь описывать операторы сравнения для reference_wrapper, сравнивать надо identity ссылаемых объектов, а не содержимое.

Если же охота рассматривать указатели не как identity, а как агрегаторы, "превращающие" ссылочное владение по семантике к владению по значению, то надо соотв. распространять константность:
http://www.rsdn.org/forum/cpp/8582434.1

В любом случае, пример твой некорректен согласно логике спора, бо ты пытаешься рассуждать об потенциальных ошибках обеспечения константности-иммутабельности, где ошибки можно допустить и в джаве (и где угодно) в попытках обеспечения этой иммутабельности.

Предлагаю рассуждать лишь о сценариях, где эта иммутабельность/константность обеспечивается корректно в обоих случаях и сравнивать только прилагаемые усилия. ))
Re[58]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 08:49
Оценка:
Здравствуйте, ·, Вы писали:

R>>Потому что константность ссылки/указателя не гарантируют неизменности адресуемых данных. И тем не менее, программист МОЖЕТ обеспечить реальную константность адресуемых данных. И в этом случае их неизменность будет гарантирована в well-defined программе. Короче говоря, да, в этой области больше возможностей выстрелить себе в ногу. Но и возможность писать добротные надежные программы тоже есть.

·>Я это прекрасно знаю. Ровно то же и в java. Просто T4r4sB заявил
Автор: T4r4sB
Дата: 12.05.23
, что в C++ есть какая-то защита в виде const. Да не даёт const ровным счётом ничего.


Даёт экономию труда примерно вдвое в обсуждаемых сценариях.


·>Только если либо копия передаётся, либо передача ownership, и это немного помогает в некоторых случаях, но возможностей стрельнуть в ногу всё равно дофига.


Возможностей стрельнуть себе в ногу дофига где угодно.
Тут рассуждения такие: меньше кода — меньше ошибок.
Re[87]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 09:10
Оценка: +1 -1
TB>>>Не понял проблемы. Да, адрес у объектов один и тот же
σ>>У объектов? При NRVO это один объект.

V>Дудки! ))

V>Это одна область памяти, в которой по очереди живут два объекта.



[class.copy.elision]/1: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

В общем, уровень (не)компетентности понятен. Оттуда и ощущения/заявления, что «всё просто».
  Скрытый текст
— Да что тут предлагать?.. А то пишут, пишут… Конгресс, немцы какие-то… Голова пухнет. Взять все, да и поделить…

— Да какой тут способ, дело не хитрое.
Re[87]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 09:12
Оценка:
σ>>>>Т.е. внутри buildMap result обозначает объект вне лайфтайма? Значит на нём нельзя вызывать методы.

TB>>>Не понял проблемы. Да, адрес у объектов один и тот же


σ>>У объектов? При NRVO это один объект.


TB>>>но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.


σ>>Что значит «считается»?


S>Не очень понятна суть вопросов.


По невтемному примеру я понял.

S> В С++ даже у константных объектов есть период времени, когда они константами не считаются


Как это относится к коду в https://rsdn.org/forum/cpp/8581544.1
Автор: vdimas
Дата: 16.08.23
?
Re[88]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 18.08.23 09:35
Оценка:
Здравствуйте, σ, Вы писали:

TB>>>>но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно.


σ>>>Что значит «считается»?


S>>Не очень понятна суть вопросов.


σ>По невтемному примеру я понял.


А я не понял вопроса "Что значит «считается»?" относительно написанного тов.T4r4sB "но в одном контексте считается, что по этому адресу объект менять нельзя, а в другом — что можно."

Поэтому и обратился к вам за разъяснением.

S>> В С++ даже у константных объектов есть период времени, когда они константами не считаются


σ>Как это относится к коду в https://rsdn.org/forum/cpp/8581544.1
Автор: vdimas
Дата: 16.08.23
?


Это демонстрация сказанного тов.T4r4sB о том, что в одном контексте объект не константа, а в другом контексте уже константа. И все это относится к вашему вопросу "Что значит «считается»?"
Re[89]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 09:56
Оценка: +1
S>>> В С++ даже у константных объектов есть период времени, когда они константами не считаются

σ>>Как это относится к коду в https://rsdn.org/forum/cpp/8581544.1
Автор: vdimas
Дата: 16.08.23
?


S>Это демонстрация сказанного тов.T4r4sB о том, что в одном контексте объект не константа, а в другом контексте уже константа.


Чел… Есть вполне чоткое определение что такое константный объект https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const. И «контекстов» там как-то не замечено.
И во время конструирования в твоём примере объект тоже константный. Или, по-твоему, раз *this не const-qualified, это доказывает, что объект не константный?
Отредактировано 18.08.2023 9:56 σ . Предыдущая версия .
Re[90]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 18.08.23 10:13
Оценка: -1
Здравствуйте, σ, Вы писали:

S>>>> В С++ даже у константных объектов есть период времени, когда они константами не считаются


σ>>>Как это относится к коду в https://rsdn.org/forum/cpp/8581544.1
Автор: vdimas
Дата: 16.08.23
?


S>>Это демонстрация сказанного тов.T4r4sB о том, что в одном контексте объект не константа, а в другом контексте уже константа.


σ>Чел… Есть вполне чоткое определение что такое константный объект https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const. И «контекстов» там как-то не замечено.


Есть у меня подозрение, что определение из стандарта в данном случае валидно для писателей компиляторов и статических анализаторов, а не для простого пользователя языка.

σ>И во время конструирования в твоём примере объект тоже константный. Или, по-твоему, раз *this не const-qualified, это доказывает, что объект не константный?


Если объект можно изменить, то он не константный, как-то так, да.
Re[88]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 10:41
Оценка:
Здравствуйте, σ, Вы писали:

V>>Дудки! ))

V>>Это одна область памяти, в которой по очереди живут два объекта.

σ>[class.copy.elision]/1: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


И что, у тебя возникли проблемы с прочтением?
Описаны внутренние подробности реализации трюка.


σ>В общем, уровень (не)компетентности понятен.


Было бы понятно — не задавал бы глупых вопросов.
Согласно семантике речь идёт о двух разных объектах и эта семантика гарантируется.
Не согласен — обоснуй.

А что эту семантику можно реализовать через ссылку на одну и ту же область памяти в различных точках программы — так в этом и состоит суть RV-оптимизации. ))
Но эти ссылки никогда не валидны одновременно, во что тебя уже тыкали.


σ>— Да какой тут способ, дело не хитрое.


Угу, ты пытался рассуждать о неких проблемах.
Сформулировать проблему ты не смог, я попытался тебе помочь:
http://www.rsdn.org/forum/cpp/8582417.1
(описан единственный сценарий, где две ссылки на объект живы одновременно)

Давай ты включишь уже моск и попытаешься, таки, сформулировать проблему.
Можно своими словами, бгг..

От одного сотрясения воздуха абревиатурами RVO/NRVO твои тараканы понятнее не становятся.
Re[90]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 11:11
Оценка:
Здравствуйте, σ, Вы писали:

S>>Это демонстрация сказанного тов.T4r4sB о том, что в одном контексте объект не константа, а в другом контексте уже константа.

σ>Чел… Есть вполне чоткое определение что такое константный объект https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const. И «контекстов» там как-то не замечено.

А что ты хотел там увидеть?
Любой константный объект размером более машинного слова "унутре" всё-равно инициализируется за несколько операций, т.е. поля объекта при инициализации последовательно мутируются.
Разве это требуется дополнительно озвучивать?


σ>И во время конструирования в твоём примере объект тоже константный.


Каким образом? ))
Конструктор объекта не имеет понятия — создаёт ли он константный объект или мутабельный.
Re[82]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 11:29
Оценка:
Здравствуйте, ·, Вы писали:

V>>В шарпе для такого сценария есть отдельно иммутабельный аналог map, и отдельно мутабельный builder для него.

V>>В С++ не потребовалось создавать две сущности.
·>Именно, то же самое на шарпах делается с помощью интерфейса.

Интерфейсы и в плюсах доступны.
И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.

Просто это слишком частый сценарий, поэтому органично включён в язык, дабы достигать того же самого без лишних приседаний.


·>А две сущности в C++ тоже есть, просто неявно. Вместо явного интерфейса делается пара const- и просто-методов.


Так мы только выразительность языков и обсуждаем.


·>Константные объекты появляются не магически, а в определениях соответствующих полей и методов.


И в правилах языка, где константные методы можно вызывать у неконстантного объекта, а наоборот нет.

Например, св-во size() (count, amount и т.д.) определены как const, соответственно, описаны однажды для константного и неконстантного объекта.
И всё это продолжает работать в таких сценариях:
template<typename T>
void const logCollection(const T & collection) { ... }

// мутабельный объект
auto cl = makeColllection();

auto size = cl.size(); // закешировали размер
logCollection(cl); // отдали куда-то по константной ссылке

for(size_t i = 0; i < size; i++) // незачем запрашивать размер коллекции заново



V>>Этот сценарий может возникнуть не только вокруг иммутабельного map, где в шарпе постелили соломку, а вообще везде.

·>И там и там надо вводить два типа. Ведь T и const T это тоже разные типы.

Да.
Но описание типа программистом — одно.


V>>Собсно, только об этом и говорится в обсуждении (многократно по кругу) — что практически любой мутабельный тип можно использовать в т.ч. в иммутабельных сценариях.

·>"Практически" в том смысле если для типа правильно спроектирован const подтип. Ровно та же петрушка, что и с интерфейсом.

Разумеется.
Например, в шарпе интерфейс IEnumerator имеет read-only св-во Current.

Т.е., итераторы на интерфейсах сделаны не только потому что невозможно было накрутить логику как в плюсах через begin/end (в нынешнем шарпе уже можно сделать достаточно близко к плюсовомоу подходу, получив дешевизну), но еще потому что ДРУГОЙ интерфейс обеспечивает ДРУГУЮ семантику. В данном случае IEnumerator — это read-only семантика, т.е. употребима к мутабельным и немутабельным типам. В итоге для каждой коллекции приходится описывать еще и енумератор.

А вот если речь должна идти про сами типы-коллекции, то появляются пары Span/ReadOnlySpan, Memory/ReadOnlyMemory и т.д.

И это еще в шарпе по-лёгкoму, т.к. язык позволяет определять операторы преобразования, поэтому смогли определить неявное конструирование ReadOnly-версий из мутабельных.
В джаве пришлось бы делать двойную работу, окучивая каждую пару.


V>>Остальные сценарии, когда мутабельный объект подаётся по константной ссылке — это просто удобные гарантии, т.к. после вызова метода с таким аргументом ты можешь в коде рассуждать о том, что целевой объект в результате вызова некоей ф-ии с им-аргументом, не изменился.

·>Аналог final.

Не, final-метод в джаве обозначает другое.
Тут аналог readonly-метода в шарпе, но там оно допустимо только для методов структур.
Для GC-классов нет такой возможности.

Но в случае структур, да, шарп уже позволяет повторять семантику C++.


·>Суть моего тезиса в том, что семантика const в других ЯП выражается тоже, просто через другие механизмы языка.


Суть в том, что иммутабельность — такой же "трюк", облегчающий программистам жизнь, как и куча других.

Разумеется, иммутабельность можно обеспечить ср-вами любого языка, обладающего развитыми ср-вами инкапсуляции, и безо-всяких плюсовых const.
(а где эти ср-ва не развиты — там часто данные только иммутабельны, бгг, как в FP-языках)

Просто иммутабельность, всвязи с ростом многопоточности, ростом размеров оперативки (что привело к созданию больших объёмов данных в памяти) и постепенным улучшением оптимизирующих компиляторов, стала играть существенную роль в современном дизайне ПО.

И тут С++ задолго до, как грится, оказался к этому готов. ))

А вот почему более поздние джава и шарп оказались не готовы — вопрос вопросов, однако.
Отредактировано 18.08.2023 11:43 vdimas . Предыдущая версия . Еще …
Отредактировано 18.08.2023 11:40 vdimas . Предыдущая версия .
Отредактировано 18.08.2023 11:39 vdimas . Предыдущая версия .
Отредактировано 18.08.2023 11:34 vdimas . Предыдущая версия .
Re[89]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 11:31
Оценка: :)
V>>>Дудки! ))
V>>>Это одна область памяти, в которой по очереди живут два объекта.

σ>>[class.copy.elision]/1: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


V>И что, у тебя возникли проблемы с прочтением?


Похоже, у тебя возникли, раз ты утверждаешь, что объекта якобы два.

V>Описаны внутренние подробности реализации трюка.


Что значит внутренние?

σ>>В общем, уровень (не)компетентности понятен.


V>Было бы понятно — не задавал бы глупых вопросов.

V>Согласно семантике речь идёт о двух разных объектах и эта семантика гарантируется.

Гарантируется, что при NRVO объект один и тот же.

V>Не согласен — обоснуй.


У тебя возникли проблемы с прочтением?

V>А что эту семантику можно реализовать через ссылку на одну и ту же область памяти в различных точках программы — так в этом и состоит суть RV-оптимизации. ))


Какие ещё ссылки? У переменных result и someDictionary даже тип не ссылочный)))

V>Но эти ссылки никогда не валидны одновременно, во что тебя уже тыкали.


И дальше что? Операции происходят над объектом, а не «ссылками», а объект в обоих случаях один и тот же.

σ>>— Да какой тут способ, дело не хитрое.


V>Угу, ты пытался рассуждать о неких проблемах.


Это широко известная проблема (в узких кругах)

V>Сформулировать проблему ты не смог


Это ты не смог понять

V>я попытался тебе помочь


Cura te ipsum

V>Давай ты включишь уже моск и попытаешься, таки, сформулировать проблему.

V>Можно своими словами, бгг..

Стёкла не выдави своим раздутым ЧСВ

V>От одного сотрясения воздуха абревиатурами RVO/NRVO твои тараканы понятнее не становятся.


От одного сотрясения воздуха словами про "контекст" или "внутренние подробности" твой бред ответом на проблему не становится
Re[90]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 11:58
Оценка:
Здравствуйте, σ, Вы писали:

σ>Похоже, у тебя возникли, раз ты утверждаешь, что объекта якобы два.


Согласно семантике — два.
Согласно способу реализации — соптимизировали в один.


V>>Описаны внутренние подробности реализации трюка.

σ>Что значит внутренние?

Что и без этой подробности семантика твоей программы не изменится.


V>>Было бы понятно — не задавал бы глупых вопросов.

V>>Согласно семантике речь идёт о двух разных объектах и эта семантика гарантируется.
σ>Гарантируется, что при NRVO объект один и тот же.

Оптимизации не являются обязательными.
Более того, несут с собой некоторые ограничения:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

В стандарте с С++17 рекомендуется RV-оптимизация только безымянного объекта, т.е. мой пример под это НЕ попадает.

А для моего примера в стандарте сказано — компилтору разрешается убирать лишнее копирование (или перемещающее копирование).


V>>Не согласен — обоснуй.

σ>У тебя возникли проблемы с прочтением?

У тебя возникли проблемы с формулировкой проблемы.


V>>А что эту семантику можно реализовать через ссылку на одну и ту же область памяти в различных точках программы — так в этом и состоит суть RV-оптимизации. ))

σ>Какие ещё ссылки? У переменных result и someDictionary даже тип не ссылочный)))

Мда...
Согласно определению, переменная — это адрес объекта.
Переменная-поле — адрес от "начала" объекта.
Глобальная — адрес в глобальном сегмента данных.
Локальная — адрес в локальном фрейме стека.

В общем, ликбез — доступ к полям объектов или автоматическим переменным на стеке всегда косвенный.
Прямой доступ возможен только к глобальным переменным.


V>>Но эти ссылки никогда не валидны одновременно, во что тебя уже тыкали.

σ>И дальше что? Операции происходят над объектом, а не «ссылками», а объект в обоих случаях один и тот же.

Операции над объектами происходят через ссылание на них — через имя переменной, либо через явные ссылочные типы данных.


σ>>>— Да какой тут способ, дело не хитрое.

V>>Угу, ты пытался рассуждать о неких проблемах.
σ>Это широко известная проблема (в узких кругах)

Но сформулировать не можешь?
Так и запишем.


V>>Сформулировать проблему ты не смог

σ>Это ты не смог понять

Я пока не видел формулирования, т.е. понимать пока нечего.
Я попытался тебе помочь, но ты там не в состоянии ответить:
http://www.rsdn.org/forum/cpp/8582417.1


V>>Давай ты включишь уже моск и попытаешься, таки, сформулировать проблему.

V>>Можно своими словами, бгг..
σ>Стёкла не выдави своим раздутым ЧСВ

Чья бы корова мычала. ))
Ты зачем-то начал хамить в банальном, в общем-то, случае.
Я тоже в детстве психовал, когда не сразу что-то понимал... Но так то в детстве! ))


V>>От одного сотрясения воздуха абревиатурами RVO/NRVO твои тараканы понятнее не становятся.

σ>От одного сотрясения воздуха словами про "контекст" или "внутренние подробности" твой бред ответом на проблему не становится

Второй раз я дал тебе ссылку, где давно можно было бы ответить по-существу, вместо пререканий.
Отредактировано 18.08.2023 11:59 vdimas . Предыдущая версия .
Re[19]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 18.08.23 12:23
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Проблема усугубляется тем, что требования к аллокаторам плохо совместимы с требованиями к placment new (хотя для меня этот вопрос до конца не ясен).


ИМХО, ситуация перезаписи объекта через placement new мало отличается от такой:
const SomeObj * a = new SomeObj(42);
delete a;
const SomeObj * b = new SomeObj(43);

std::cout << a->value();

где a и b имеют одинаковый адрес.


BFE>В целом получается, что есть много старого кода формально с UB и это мешает оптимизации


Оптимизации мешает отсутствие полного знания о жизненном цикле объекта.
Re[90]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 18.08.23 12:47
Оценка: +1 -1
Здравствуйте, σ, Вы писали:

σ>Похоже, у тебя возникли, раз ты утверждаешь, что объекта якобы два.


Это у тебя проблемы с пониманием, если ты не можешь понять по контексту, в каком случае имеется в виду семантика, а в каком — особенности внутренней реализации.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[91]: Когда это наконец станет defined behavior?
От: σ  
Дата: 18.08.23 13:25
Оценка: +1 :))
σ>>Похоже, у тебя возникли, раз ты утверждаешь, что объекта якобы два.

V>Согласно семантике — два.


Да нет, согласно семантике — один. Это вполне себе наблюдаемое поведение. Различить, было NRVO или нет — возможно. As-if rule тут не катит. Поэтому стандарт явно оговаривает этот случай.

V>>>Описаны внутренние подробности реализации трюка.

σ>>Что значит внутренние?

V>Что и без этой подробности семантика твоей программы не изменится.


Лол)))
Когда объекта два, то в функции объект неконстантный, а вне — константный и всё просто: можно менять в функции и нельзя вне.
Когда объект один в обоих местах, то он либо константный и там и там, либо не там и не там. Если он константный, то его модифицировать его в функции это UB. А если неконстантный, то его можно модифицировать вне функции, это не UB.

Это называется «семантика не изменится»?

V>Оптимизации не являются обязательными.

V>Более того, несут с собой некоторые ограничения:
V>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

V>В стандарте с С++17 рекомендуется RV-оптимизация только безымянного объекта, т.е. мой пример под это НЕ попадает.


V>А для моего примера в стандарте сказано — компилтору разрешается убирать лишнее копирование (или перемещающее копирование).


Да, в твоём примере NRVO не наблюдаемо, но сделать его наблюдаемым и задетектить можно.

V>>>А что эту семантику можно реализовать через ссылку на одну и ту же область памяти в различных точках программы — так в этом и состоит суть RV-оптимизации. ))

σ>>Какие ещё ссылки? У переменных result и someDictionary даже тип не ссылочный)))

V>Мда...

V>Согласно определению, переменная — это адрес объекта.

В стандарте слегка другое определение))) (Впрочем, оно кривое, но правильное всё равно будет другм)

V>Переменная-поле — адрес от "начала" объекта.


Non-static data member по определению не считается/не наывается variable (переменной).

V>Глобальная — адрес в глобальном сегмента данных.

V>Локальная — адрес в локальном фрейме стека.

V>В общем, ликбез — доступ к полям объектов или автоматическим переменным на стеке всегда косвенный.

V>Прямой доступ возможен только к глобальным переменным.

Так. И как эта простыня текста отвечает на «какие ещё ссылки?»

V>>>Но эти ссылки никогда не валидны одновременно, во что тебя уже тыкали.

σ>>И дальше что? Операции происходят над объектом, а не «ссылками», а объект в обоих случаях один и тот же.

V>Операции над объектами происходят через ссылание на них — через имя переменной, либо через явные ссылочные типы данных.


НУ И ДАЛЬШЕ-ТО ЧТО????????????
Константность — это свойство объекта. UB — при модификации константного объекта. Какая разница, сколько где каких ссылок на него, и через какие из них это произойдёт?

σ>>>>— Да какой тут способ, дело не хитрое.

V>>>Угу, ты пытался рассуждать о неких проблемах.
σ>>Это широко известная проблема (в узких кругах)

V>Но сформулировать не можешь?

V>Так и запишем.

Это ты тормозишь на ровном месте. Ладно, попробую ещё раз.
При NRVO переменная, которая инициализируется вызовом функции, и некая переменная внутри этой функции, обозначают один и тот же объект. Только вот может быть так, что снаружи переменная типа const T, а внутри — T. Но тип объекта это отдельная от типов переменной вещь, и раз объект один, то и тип один. Так какой объект — константый или нет?
Re[92]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 20.08.23 18:51
Оценка: -2
Здравствуйте, σ, Вы писали:

V>>Согласно семантике — два.

σ>Да нет, согласно семантике — один.

Два.


σ>Это вполне себе наблюдаемое поведение.


В этом суть оптимизации.
Точно такая же происходит здесь:
const SomeObj obj = SomeObj(args);

Согласно семантике, создаётся временный безымянный объект и копируется (либо перемещается) в целевую переменную obj.
Лишнего копирования/перемещения можно избежать.
При возврате по значению применяется ровно та же логика.


σ>Различить, было NRVO или нет — возможно.


Только если конструкторы/деструкторы имеют побочные эффекты.


σ>As-if rule тут не катит. Поэтому стандарт явно оговаривает этот случай.


Объясняет для непонятливых, скорее, почему не надо разбрасываться побочными эффектами в конструторах и деструкторах. ))


σ>Когда объекта два, то в функции объект неконстантный, а вне — константный и всё просто: можно менять в функции и нельзя вне.


Это не принципиально, ровно так же как не принципиально в примере выше при инициализации.

И ты уже порядком поднадоел своей непонятливостью, положа руку на.
Если выражение справа исполняется лишь до тех пор, пока выражение слева является неинициализированным — то какая нахрен польза от твоих спекуляций?
Медитируй над продвижением точки исполнения, пальчиком по экрану поводи, может дойдёт. ))

Ну нельзя в императивной программе рассуждать об одновременности событий из одного потока исполнения.
А ты вот так запросто об этом рассуждаешь.
Позорище, сорри.
Re[91]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 11:57
Оценка: :)
σ>>И во время конструирования в твоём примере объект тоже константный.

V>Каким образом? ))


По определению, которое я линканул. Его ты, видимо, тоже не смог понять

V>Конструктор объекта не имеет понятия — создаёт ли он константный объект или мутабельный.


И? Константный объект или нет зависит от его типа. А не от того, что там понимает конструктор. Объект вообще может не конструктором инициализироваться.
Ты очень много пишешь всяких утверждений, которые вообще непонятно на что влияют. Ты просто любишь своими наблюдениями делиться?
Re[93]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 11:57
Оценка: :)
V>>>Согласно семантике — два.
σ>>Да нет, согласно семантике — один.

V>Два.


Симптоматично, что ни одного пруфа от тебя до сих пор не было.

σ>>Это вполне себе наблюдаемое поведение.


V>В этом суть оптимизации.

V>Точно такая же происходит здесь:
V>
const SomeObj obj = SomeObj(args);

V>Согласно семантике, создаётся временный безымянный объект и копируется (либо перемещается) в целевую переменную obj.

Или не создаётся и не копируется, тоже «согласно семантике», а не «способу реализации»

V>Лишнего копирования/перемещения можно избежать.

V>При возврате по значению применяется ровно та же логика.

Только при возврате по значению может быть несколько переменных с разной константностью, обозначающих один и тот же объект. И тогда возникают некоторые вопросы.

σ>>Различить, было NRVO или нет — возможно.


V>Только если конструкторы/деструкторы имеют побочные эффекты.


Не только. Но даже если бы было и только — какая разница?

σ>>As-if rule тут не катит. Поэтому стандарт явно оговаривает этот случай.


V>Объясняет для непонятливых, скорее, почему не надо разбрасываться побочными эффектами в конструторах и деструкторах. ))


Пруф можно?

σ>>Когда объекта два, то в функции объект неконстантный, а вне — константный и всё просто: можно менять в функции и нельзя вне.


V>Это не принципиально, ровно так же как не принципиально в примере выше при инициализации.


Разница между программой без UB и с UB — не принципиальна?

V>И ты уже порядком поднадоел своей непонятливостью, положа руку на.


Забавные проекции.

V>Если выражение справа исполняется лишь до тех пор, пока выражение слева является неинициализированным — то какая нахрен польза от твоих спекуляций?


Что ты называешь спекуляциями?
Отредактировано 21.08.2023 11:58 σ . Предыдущая версия .
Re[92]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 12:15
Оценка:
Здравствуйте, σ, Вы писали:

σ>И? Константный объект или нет зависит от его типа. А не от того, что там понимает конструктор. Объект вообще может не конструктором инициализироваться.


Интересно (правда интересно, здесь нет ни иронии, ни сарказма), а чем кроме конструктора может инициализироваться константный объект?
Вот тупо есть:
const T immutable_value;

Чем его можно проинициализировать кроме как конструктором?

Оно понятно, что в C++23 появился std::start_lifetime_as, посредством которого можно сделать:
alignas(T) std::byte buffer[sizeof(T)];
read_some_data(buffer);
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);

Но в этом случае мы, по сути имеем лишь константный указатель на неконстантный объект.
Re[12]: Почему?
От: Sm0ke Россия ksi
Дата: 21.08.23 12:51
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, T4r4sB, Вы писали:


TB>>Проверил разные версии кланга, да, он явно продвинутее, чем гцц.


_>Несомненно продвинутее

_>https://godbolt.org/z/EY73G4nMr

bool f1() { bool x; return x||!x; }

inline bool f2(bool x) { return x||!x; }

bool f3() { bool x; return f2(x); }


CLANG
f1():                                 # @f1()
        xorl    %eax, %eax
        retq
f3():                                 # @f3()
        movb    $1, %al
        retq


GCC 11.2
f1():
        movl    $1, %eax
        ret
f3():
        movl    $1, %eax
        ret


msvc 19.30
bool f1(void) PROC                                        ; f1, COMDAT
        mov     al, 1
        ret     0
bool f1(void) ENDP                                        ; f1

x$ = 8
bool f2(bool) PROC                                  ; f2, COMDAT
        mov     al, 1
        ret     0
bool f2(bool) ENDP                                  ; f2

bool f3(void) PROC                                        ; f3, COMDAT
        mov     al, 1
        ret     0
bool f3(void) ENDP                                        ; f3


p/s: это при -O2

Почему?
Re[93]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 12:52
Оценка:
σ>>И? Константный объект или нет зависит от его типа. А не от того, что там понимает конструктор. Объект вообще может не конструктором инициализироваться.

S>Интересно (правда интересно, здесь нет ни иронии, ни сарказма), а чем кроме конструктора может инициализироваться константный объект?


Действительно, чем же…
const int i = 0;
const struct S { int i; } s = {0};
Re[93]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 12:54
Оценка:
S>Оно понятно, что в C++23 появился std::start_lifetime_as, посредством которого можно сделать:
S>
alignas(T) std::byte buffer[sizeof(T)];
read_some_data(buffer);
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);

S>Но в этом случае мы, по сути имеем лишь константный указатель на неконстантный объект.

std::start_lifetime_as<const T> создаёт объект типа const T, т.е константный.
Re[94]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 13:01
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>И? Константный объект или нет зависит от его типа. А не от того, что там понимает конструктор. Объект вообще может не конструктором инициализироваться.


S>>Интересно (правда интересно, здесь нет ни иронии, ни сарказма), а чем кроме конструктора может инициализироваться константный объект?


σ>Действительно, чем же…

σ>
const int i = 0;
σ>const struct S { int i; } s = {0};


Хорошо бы понять что здесь есть объект. Надо полагать, что `int i`.
Re[94]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 13:04
Оценка:
Здравствуйте, σ, Вы писали:

S>>Оно понятно, что в C++23 появился std::start_lifetime_as, посредством которого можно сделать:

S>>
σ>alignas(T) std::byte buffer[sizeof(T)];
σ>read_some_data(buffer);
σ>const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);
σ>

S>>Но в этом случае мы, по сути имеем лишь константный указатель на неконстантный объект.

σ>std::start_lifetime_as<const T> создаёт объект


Создает? Да ладно!

Он, вроде бы, к созданию объекта чуть меньше, чем никак. Это всего лишь указание компилятору считать полученный указатель валидным указателем на объект, время жизни которого было начато вне поля зрения компилятора.
Отредактировано 21.08.2023 13:05 so5team . Предыдущая версия .
Re[95]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 13:15
Оценка: +1
σ>>std::start_lifetime_as<const T> создаёт объект

S>Создает? Да ладно!


???

Effects: Implicitly creates objects within the denoted region consisting of an object a of type T
Отредактировано 21.08.2023 13:23 σ . Предыдущая версия .
Re[96]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 13:30
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>std::start_lifetime_as<const T> создаёт объект


S>>Создает? Да ладно!


σ>Effects: Implicitly creates objects within the denoted region consisting of an object a of type T


И?

Вот у нас два примера. Первый:
alignas(T) std::byte buffer[sizeof(T)];
read_some_data(buffer); // (1) собственно здесь создание объекта и происходит.
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);


Второй:
alignas(T) std::byte buffer[sizeof(T)]; // Какой-то мусор.
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);


Ну и как std::start_lifetime_as создаст во втором случае объект типа T? И откуда он возьмет его корректный начальный инвариант?

В том-то и дело, что implicitly creates -- это такое высказывание для стандарта, которое означает начало времени жизни для объекта, который был создан вне поля видимости компилятора. Отсюда и всякие implicit-lifetime types, implicitly creates и пр.
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 13:53
Оценка: +1
S>Здравствуйте, σ, Вы писали:

σ>>>>std::start_lifetime_as<const T> создаёт объект


S>>>Создает? Да ладно!


σ>>Effects: Implicitly creates objects within the denoted region consisting of an object a of type T


S>И?


S>Вот у нас два примера. Первый:

S>
alignas(T) std::byte buffer[sizeof(T)];
read_some_data(buffer); // (1) собственно здесь создание объекта и происходит.
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);


S>Второй:

S>
alignas(T) std::byte buffer[sizeof(T)]; // Какой-то мусор.
const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);


S>Ну и как std::start_lifetime_as создаст во втором случае объект типа T?


Написано же: implicitly.

S> И откуда он возьмет его корректный начальный инвариант?


Чё возьмёт?! Можно в Preconditions start_lifetime_as увидеть хоть что-то про «корректный начальный инвариант»?

S> В том-то и дело, что implicitly creates -- это такое высказывание для стандарта, которое означает начало времени жизни для объекта


Время жизни объекта в стандарте описывается словами «object lifetime». А создание — create/creates/created etc.

S> который был создан вне поля видимости компилятора.


Когда?! Где?!

Если ты имеешь в виду абстрактную машину C++, то никакие объекты не создаются «вне» её. Был пропозал (или несколько) про «экспорт»/«импорт» объектов из/в абстрактную машину (чтобы работу нескольких процессов через шареную память можно было описать), но они так и остались пропозалами.
Re[94]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 14:26
Оценка:
Здравствуйте, σ, Вы писали:

σ>Разница между программой без UB и с UB — не принципиальна?


Про какие фантастические УБ ты говоришь?
Давай реальный пример, а то пустая болтовня. И походу ты так и не понял в чем разница между объектом и местом в памяти
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[95]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 14:29
Оценка: :)
σ>>Разница между программой без UB и с UB — не принципиальна?

TB>Про какие фантастические УБ ты говоришь?


Читай выше, где я описал разницу между выполнением с NRVO и без. Если при NRVO объект константный, то внутри функции его менять — UB.

TB>Давай реальный пример, а то пустая болтовня.


Define «реальный». Ну и вообще, сначала на мой вопрос про то, какой объект ответь.

TB>И походу ты так и не понял в чем разница между объектом и местом в памяти


Чо за место в памяти? https://timsong-cpp.github.io/cppwp/n4868/intro.memory#def:memory_location, что ли?
Отредактировано 21.08.2023 14:34 σ . Предыдущая версия .
Re[96]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 14:36
Оценка: +1 -1
Здравствуйте, σ, Вы писали:

σ>>>Разница между программой без UB и с UB — не принципиальна?


TB>>Про какие фантастические УБ ты говоришь?


σ>Читай выше, где я описал разницу между выполнением с NRVO и без. Если при NRVO объект константный, то внутри функции его менять — UB.


Обоснуй что это УБ, реальным примером. Иначе получается что ты не умеешь читать стандарт.
Будет смешно если окажется что компилятор считает что семантически объект внутри функции — другой. Хотя и имеет тот же адрес в памяти.

TB>>Давай реальный пример, а то пустая болтовня.


σ>Define «реальный»


Ты тролль или дурачок?
Код который показывает это самое УБ про которое ты говоришь.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 14:48
Оценка: +1 -1
TB>>>Давай реальный пример, а то пустая болтовня.

σ>>Define «реальный»


TB>Ты тролль или дурачок?


Это понимать как то, что определения не будет?

σ>>>>Разница между программой без UB и с UB — не принципиальна?


TB>>>Про какие фантастические УБ ты говоришь?


σ>>Читай выше, где я описал разницу между выполнением с NRVO и без. Если при NRVO объект константный, то внутри функции его менять — UB.


TB>Обоснуй что это УБ


Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1

TB>Будет смешно если окажется что компилятор считает что семантически объект внутри функции — другой. Хотя и имеет тот же адрес в памяти.


Если по семантике C++ это один и тот же объект, какая разница, что считает компилятор или твой сосед по парте?
Re[98]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 14:52
Оценка:
Здравствуйте, σ, Вы писали:


TB>>>>Давай реальный пример, а то пустая болтовня.


σ>>>Define «реальный»


TB>>Ты тролль или дурачок?


σ>Это понимать как то, что определения не будет?


Уводишь разговор в сторону? Я могу это понимать как слив?

TB>>Обоснуй что это УБ


σ>Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1


Балабол ты форумный, на реальном примере проиллюстрируешь это уб?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[98]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 14:52
Оценка:
Здравствуйте, σ, Вы писали:

S>>Вот у нас два примера. Первый:

S>>
σ>alignas(T) std::byte buffer[sizeof(T)];
σ>read_some_data(buffer); // (1) собственно здесь создание объекта и происходит.
σ>const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);
σ>


S>>Второй:

S>>
σ>alignas(T) std::byte buffer[sizeof(T)]; // Какой-то мусор.
σ>const T * ptr_to_immutable_value = std::start_lifetime_as<const T>(buffer);
σ>


S>>Ну и как std::start_lifetime_as создаст во втором случае объект типа T?


σ>Написано же: implicitly.


Ну так это софистика для стандарта, нужен им был какой-то специальный термин, вот они и придумали для себя implicitly creates.
Обычный разработчик как этот implicitly creates должен воспринимать? Уж точно не как creates, который для new или для обычного создания объекта на стеке.

S>> И откуда он возьмет его корректный начальный инвариант?


σ>Чё возьмёт?!


Нормальное начальное состояние для объекта он где возьмет?

Вот когда мы делаем const T * p = new T(); мы же создаем объект и получаем его в неком нормальном начальном состоянии. Вызвав только new, ничего
больше не делая. А в случае start_lifetime_as мы типа создали, но если до этого пару-тройку обязательных приседаний не сделали, то никакого создания у нас не произойдет.

S>> В том-то и дело, что implicitly creates -- это такое высказывание для стандарта, которое означает начало времени жизни для объекта


σ>Время жизни объекта в стандарте описывается словами «object lifetime». А создание — create/creates/created etc.


Еще раз вам намекаю: то, что написано в стандарте, написано для разработчиков компилятора, анализаторов и стандартной библиотеки.
Пользователям языка текст стандарта нужно на нормальный человеческий язык переводить, чтобы было понимание, что "implicitly creates" к "creates" отношения не имеет.

S>> который был создан вне поля видимости компилятора.


σ>Когда?! Где?!


В первом примере в точке (1).

σ>Если ты имеешь в виду абстрактную машину C++, то никакие объекты не создаются «вне» её.


Я про программы, которые пишут люди. И про людей, которые внезапно сталкиваются с ситуацией, что вот так просто:
unsigned char buffer[4096];
read_data(buffer);
const T * p = reinterpreter_cast<const T>(&buffer[some_offset]);

в C++ поступать нельзя. Потому что компилятор должен понимать откуда у него объекты берутся. И если внезапно появляются объекты, про которые компилятор не знает (как в приводимых мной примерах), то компилятор не будет считать указатель валидным (т.е. указывающим на объект для которого где-то корректно начался lifetime). Отсюда и надобность в start_lifetime_as. И что start_lifetime_as -- это никакое не создание объекта, а суть ублажение компилятора, чтобы он не сотворил каких-то нелепых оптимизаций.

Я, конечно, от души завидую тем, кто понимает что есть абстрактная машина C++ и как эта компилятор работает с этой самой абстрактной машиной. Но, имхо, должны быть и более простые и понятные объяснения принципов работы C++ного кода для обычных людей.
Re[98]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 14:58
Оценка: +1
Здравствуйте, σ, Вы писали:


TB>>>>Про какие фантастические УБ ты говоришь?


σ>>>Читай выше, где я описал разницу между выполнением с NRVO и без. Если при NRVO объект константный, то внутри функции его менять — UB.


TB>>Обоснуй что это УБ


σ>Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1


Только вот фишка в том, что до выхода из функции нет никакого константного объекта. Он появляется только когда функция закончилась. Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.

Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект и изменение состояния внутри конструктора через этот указатель никакое не UB.
Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 15:19
Оценка: +1
TB>>>>>Про какие фантастические УБ ты говоришь?

σ>>>>Читай выше, где я описал разницу между выполнением с NRVO и без. Если при NRVO объект константный, то внутри функции его менять — UB.


TB>>>Обоснуй что это УБ


σ>>Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1


S>Только вот фишка в том, что до выхода из функции нет никакого константного объекта. Он появляется только когда функция закончилась.


Это когда нет NRVO. (И то, скорее константный объект появляется всё-таки до вызова функции, а его инициализация заканчивается (и, следовательно, лайфтайм начинается) после вызова. Ну это так, детали, хер с ними).
А если есть NRVO, то теперь переменная вне функции и внутри, вместо обозначения двух разных объектов, начинают обозначать один и тот же. Я выше кидал цитату про two different ways of referring to the same object.

S>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.


И каким же образом объект вдруг поменяет свою константность?

S>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект


this во время конструкции константного объекта указаывает, внезапно, на константный объект.

S>изменение состояния внутри конструктора через этот указатель никакое не UB.


Потому что так написано в стандарте https://timsong-cpp.github.io/cppwp/n4868/class.ctor.general#5
Re[92]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 21.08.23 15:22
Оценка: +1
Здравствуйте, σ, Вы писали:

σ>Лол)))

σ>Когда объекта два, то в функции объект неконстантный, а вне — константный и всё просто: можно менять в функции и нельзя вне.
σ>Когда объект один в обоих местах, то он либо константный и там и там, либо не там и не там. Если он константный, то его модифицировать его в функции это UB. А если неконстантный, то его можно модифицировать вне функции, это не UB.

(тихо хихикая) Т.е. согласно вашей логике, исходный пример
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

const std::map<int, int> someDictionary = buildMap();

— это UB, если NRVO ?

А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?
И каждый день — без права на ошибку...
Re[93]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 15:32
Оценка: :)
σ>>Лол)))
σ>>Когда объекта два, то в функции объект неконстантный, а вне — константный и всё просто: можно менять в функции и нельзя вне.
σ>>Когда объект один в обоих местах, то он либо константный и там и там, либо не там и не там. Если он константный, то его модифицировать его в функции это UB. А если неконстантный, то его можно модифицировать вне функции, это не UB.

BFE>(тихо хихикая) Т.е. согласно вашей логике, исходный пример

BFE>
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

const std::map<int, int> someDictionary = buildMap();

BFE>- это UB, если NRVO ?

Может да. Может нет. Может на это сложно/невозможно ответить.
Я об этом спросил у форумчан, но в ответ получил тонну истерики, и ни одной попытки описания поведения со ссылками на стандарт. ¯\_(ツ)_/¯

BFE>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?


Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.
Re[94]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 15:38
Оценка:
Здравствуйте, σ,
σ>Может да. Может нет. Может на это сложно/невозможно ответить.
Или ты не понимаешь смысл написанного в стандарте
Ты пример где мы можем пронаблюдать UB, покажешь?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 15:38
Оценка:
S>>> И откуда он возьмет его корректный начальный инвариант?

σ>>Чё возьмёт?!


S>Нормальное начальное состояние для объекта он где возьмет?


S>Вот когда мы делаем const T * p = new T(); мы же создаем объект и получаем его в неком нормальном начальном состоянии. Вызвав только new, ничего

S>больше не делая. А в случае start_lifetime_as мы типа создали, но если до этого пару-тройку обязательных приседаний не сделали, то никакого создания у нас не произойдет.

Я не понимаю, что ты называешь приседаниями.

S>>> В том-то и дело, что implicitly creates -- это такое высказывание для стандарта, которое означает начало времени жизни для объекта


σ>>Время жизни объекта в стандарте описывается словами «object lifetime». А создание — create/creates/created etc.


S>Еще раз вам намекаю: то, что написано в стандарте, написано для разработчиков компилятора, анализаторов и стандартной библиотеки.


Нет, написано для доярок и сталеваров.

S>Пользователям языка текст стандарта нужно на нормальный человеческий язык переводить, чтобы было понимание, что "implicitly creates" к "creates" отношения не имеет.


S>>> который был создан вне поля видимости компилятора.


σ>>Когда?! Где?!


S>В первом примере в точке (1).


σ>>Если ты имеешь в виду абстрактную машину C++, то никакие объекты не создаются «вне» её.


S>Я про программы, которые пишут люди. И про людей, которые внезапно сталкиваются с ситуацией, что вот так просто:

S>
unsigned char buffer[4096];
read_data(buffer);
const T * p = reinterpreter_cast<const T>(&buffer[some_offset]);

S>в C++ поступать нельзя.

Предполагаю, что даже на этом форуме найдутся те, кто скажет что «Это софистика для стандарта. Я всю жизнь так поступал и ничо мне за это не было, так что можно»
Re[95]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 15:47
Оценка: +1 -2 :)
σ>>Может да. Может нет. Может на это сложно/невозможно ответить.
TB>Или ты не понимаешь смысл написанного в стандарте
Или ты

TB>Ты пример где мы можем пронаблюдать UB, покажешь?


Пожалуйста:
struct S { int i; };

S f()
{
  S s;

  s.i = 0;
}

const S t = f();

При NRVO, переменные s и t обозначают один и тот же объект.
Если он константный, то его int-овый подобъект это тоже константный объект согласно https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#1.1 (a non-mutable subobject of a const object)
s.i = 0 это модификация (https://timsong-cpp.github.io/cppwp/n4868/expr.ass#2), а модифицировать константный объект — UB (https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1)

Воть :3
Re[100]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:04
Оценка:
Здравствуйте, σ, Вы писали:

S>>Вот когда мы делаем const T * p = new T(); мы же создаем объект и получаем его в неком нормальном начальном состоянии. Вызвав только new, ничего

S>>больше не делая. А в случае start_lifetime_as мы типа создали, но если до этого пару-тройку обязательных приседаний не сделали, то никакого создания у нас не произойдет.

σ>Я не понимаю, что ты называешь приседаниями.


Выделение памяти.
Присваивание значения.

Это происходит автоматически при использовании new или при размещении объекта на стеке (или при включения его внутрь другого объекта).

Ничего этого нет для start_lifetime_as.

S>>Еще раз вам намекаю: то, что написано в стандарте, написано для разработчиков компилятора, анализаторов и стандартной библиотеки.


σ>Нет, написано для доярок и сталеваров.


OK, которые специализируются на штудировании стандата для пиления компиляторов, анализаторов и стандартной библиотеки.

σ>Предполагаю, что даже на этом форуме найдутся те, кто скажет что «Это софистика для стандарта. Я всю жизнь так поступал и ничо мне за это не было, так что можно»


Если эти люди простыми словами объяснят что можно делать и почему нужно так, то здорово. А вот отсылки на фразы типа "implicitly creates..." таким описанием, к сожалению, не являются.
Re[96]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 16:08
Оценка: :)
Здравствуйте, σ, Вы писали:

TB>>Ты пример где мы можем пронаблюдать UB, покажешь?


σ>Пожалуйста:

σ>
struct S { int i; };

σ>S f()
σ>{
σ>  S s;

σ>  s.i = 0;
σ>}

σ>const S t = f();


Ну и где тут наблюдаемое уб?
Будешь придуриваться и делать вид что не понимаешь выделенное слово?

Не надо мне кивать на твое кривое толкование стандарта, покажи на онлайн компиляторе, как режимы оптимизации ломают ожидаемую логику.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[94]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:11
Оценка:
Здравствуйте, σ, Вы писали:

BFE>>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?


σ>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.


Да блин, возьмите исходный пример:
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

void useMap() {
    const std::map<int, int> someDictionary = buildMap();
    ...
}


И разверните его вот таким образом:
void __buildMap(std::byte * __result_buffer) {
  auto * __result = new(__result_buffer) std::map<int, int>();
  __result->insert(42, 43);
}

void __useMap() {
  alignas(std::map<int, int>) std::byte __buildMap_result[sizeof(std::map<int, int>)];
  __buildMap(__buildMap_result);
  const auto & someDictionary = std::start_lifetime_as<const std::map<int, int>>(__buildMap_result);
  ...
}


И?

Какие проблемы с UB?
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:17
Оценка:
TB>Ну и где тут наблюдаемое уб?

Я вполне отчётливо наблюдаю уб в том сценарии, который описал. Конкретное место и причину.

TB>Не надо мне кивать на твое кривое толкование стандарта, покажи на онлайн компиляторе, как режимы оптимизации ломают ожидаемую логику.


А какая тут ожидаемая логика?
Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:19
Оценка: :)
S>>>Вот когда мы делаем const T * p = new T(); мы же создаем объект и получаем его в неком нормальном начальном состоянии. Вызвав только new, ничего
S>>>больше не делая. А в случае start_lifetime_as мы типа создали, но если до этого пару-тройку обязательных приседаний не сделали, то никакого создания у нас не произойдет.

σ>>Я не понимаю, что ты называешь приседаниями.


S>Выделение памяти.

S>Присваивание значения.

S>Это происходит автоматически при использовании new или при размещении объекта на стеке (или при включения его внутрь другого объекта).


Это типа критерии создания объекта?

S>Ничего этого нет для start_lifetime_as.


S>>>Еще раз вам намекаю: то, что написано в стандарте, написано для разработчиков компилятора, анализаторов и стандартной библиотеки.


σ>>Нет, написано для доярок и сталеваров.


S>OK, которые специализируются на штудировании стандата для пиления компиляторов, анализаторов и стандартной библиотеки.


σ>>Предполагаю, что даже на этом форуме найдутся те, кто скажет что «Это софистика для стандарта. Я всю жизнь так поступал и ничо мне за это не было, так что можно»


S>Если эти люди простыми словами объяснят что можно делать и почему нужно так, то здорово. А вот отсылки на фразы типа "implicitly creates..." таким описанием, к сожалению, не являются.


Вполне являются.
Re[98]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 16:23
Оценка: +1 -2
Здравствуйте, σ, Вы писали:

TB>>Ну и где тут наблюдаемое уб?


σ>Я вполне отчётливо наблюдаю уб в том сценарии, который описал. Конкретное место и причину


σ>А какая тут ожидаемая логика?


Опять под дурачка косишь? Мальчик, ты балабол.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[95]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:23
Оценка:
BFE>>>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?

σ>>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.


S>Да блин, возьмите исходный пример:

S>
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

void useMap() {
    const std::map<int, int> someDictionary = buildMap();
    ...
}


S>И разверните его вот таким образом:


А почему таким, а не таким:
void useMap() { return; }


S>Какие проблемы с UB?


Да может и никаких, я не знаю, я просто спрашиваю, каким будет объект при NRVO — константным или нет.
Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:25
Оценка:
TB>>>Ну и где тут наблюдаемое уб?

σ>>Я вполне отчётливо наблюдаю уб в том сценарии, который описал. Конкретное место и причину


σ>>А какая тут ожидаемая логика?


TB>Опять под дурачка косишь? Мальчик, ты балабол.


В чём дело? Ты не можешь описать ожидаемую логику? А как ты тогда определяешь, меняет её оптимизатор или нет
Re[100]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 16:30
Оценка: -1
Здравствуйте, σ, Вы писали:

σ>В чём дело? Ты не можешь описать ожидаемую логику? А как ты тогда определяешь, меняет её оптимизатор или нет


Обдристался — признай, не будь чмошником
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[102]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:39
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>Я не понимаю, что ты называешь приседаниями.


S>>Выделение памяти.

S>>Присваивание значения.

S>>Это происходит автоматически при использовании new или при размещении объекта на стеке (или при включения его внутрь другого объекта).


σ>Это типа критерии создания объекта?


Это типа обязательные действия для того, чтобы объект был создан.

σ>Вполне являются.


Перед вами человек, для которого не является. Вопрос в том, один ли я такой.
Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:41
Оценка:
σ>>В чём дело? Ты не можешь описать ожидаемую логику? А как ты тогда определяешь, меняет её оптимизатор или нет

TB>Обдристался — признай, не будь чмошником


Дядя, с головой в порядке? Я вообще-то вопрос задавал (https://rsdn.org/forum/cpp/8581729.1
Автор: σ
Дата: 16.08.23
), как я в принципе мог, как вы выражаетесь, «обдристаться»?
Или вы перепутали кто из нас не осилил описать «ожидаему логику»?
Re[96]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:42
Оценка:
Здравствуйте, σ, Вы писали:

S>>И разверните его вот таким образом:


σ>А почему таким, а не таким:

σ>
void useMap() { return; }


Потому что в случае с "таким" нет предмета для разговора.

S>>Какие проблемы с UB?


σ>Да может и никаких, я не знаю, я просто спрашиваю, каким будет объект при NRVO — константным или нет.


Внутри функции не константным. Снаружи константным. Выше показано как такое возможно. Если при этом есть какие-то нарушения стандарта, то хотелось бы об этом услышать.
Re[95]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 16:42
Оценка: -1
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, σ, Вы писали:


BFE>>>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?


σ>>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.


S>Да блин, возьмите исходный пример:

S>
S>std::map<int, int> buildMap() {
S>    std::map<int, int> result;

S>    result.insert(42, 43); 
S>    ...
S>    return result;
S>}

S>void useMap() {
S>    const std::map<int, int> someDictionary = buildMap();
S>    ...
S>}
S>


S>И разверните его вот таким образом:

S>
S>void __buildMap(std::byte * __result_buffer) {
S>  auto * __result = new(__result_buffer) std::map<int, int>();
S>  __result->insert(42, 43);
S>}

S>void __useMap() {
S>  alignas(std::map<int, int>) std::byte __buildMap_result[sizeof(std::map<int, int>)];
S>  __buildMap(__buildMap_result);
S>  const auto & someDictionary = std::start_lifetime_as<const std::map<int, int>>(__buildMap_result);
S>  ...
S>}
S>


S>И?


представленная развертка существенно не эквивалентна исходнику, в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>
в развертке же это имя означает ссылку, и применяемый тип относится к ссылке но не к объекту, при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный
таким образом, гипотетическое UB из исходника никак не возможно в развертке так как объект перестал быть константным
Re[103]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:44
Оценка:
σ>>>>Я не понимаю, что ты называешь приседаниями.

S>>>Выделение памяти.

S>>>Присваивание значения.

S>>>Это происходит автоматически при использовании new или при размещении объекта на стеке (или при включения его внутрь другого объекта).


σ>>Это типа критерии создания объекта?


S>Это типа обязательные действия для того, чтобы объект был создан.


А можно ссылку на стандарт, плес?

σ>>Вполне являются.


S>Перед вами человек, для которого не является. Вопрос в том, один ли я такой.


Да может не один, только вот описание того, что делает start_lifetime_as, или про что там мы говорили, от числа (не)понимающих не зависит.
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 16:50
Оценка:
S>>>Какие проблемы с UB?

σ>>Да может и никаких, я не знаю, я просто спрашиваю, каким будет объект при NRVO — константным или нет.


S>Внутри функции не константным. Снаружи константным. Выше показано как такое возможно.


Выше показано два куска кода про которые утверждается что у них эквивалентное поведение.
Ток вот хорошо бы сначала поиметь описания поведения оригинального (или аналогичного упрощённого, как в https://rsdn.org/forum/cpp/8585034.1
Автор: σ
Дата: 21.08.23
) кода. (В ситуации NRVO, без NRVO вопросов нет).

S>Если при этом есть какие-то нарушения стандарта, то хотелось бы об этом услышать.


В свою очередь, хотелось бы увидеть описание поведения (с т.з. стандарта, естественно)
Re[96]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:55
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>представленная развертка существенно не эквивалентна исходнику, в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>

V>в развертке же это имя означает ссылку, и применяемый тип относится к ссылке но не к объекту, при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный

Простите за грубость, но когда вы в исходном коде видите:
const std::map<int, int> someName;

то кто вам гарантирует, что идентификатор someName означает что-то кроме ссылки после прохода оптимизатора? И вообще хоть что-то да значит?

V>таким образом, гипотетическое UB из исходника никак не возможно в развертке так как объект перестал быть константным


Я был бы признателен, если бы кто-нибудь объяснил откуда может взяться UB и вообще как результирующий константный объект может рассматриваться до завершения работы порождающей его функции.

А еще было бы круто если бы кто-нибудь из почитателей святой буквы стандарта наконец-то объяснил простую штуку:
class demo {
  int i_;
public:
  demo() {
    i_ = f();
  }
  int f() { return rand(); }
};

const demo d;

работает конструктор константного объекта, но сам объект в это время нифига не константа.

А то доказывать, что термин "implicitly creates" понятен всем и каждому, вот прям горазды. А ответить на простые вопросы так "покажите мне текст стандарта".
Re[104]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 16:57
Оценка:
Здравствуйте, σ, Вы писали:

S>>Это типа обязательные действия для того, чтобы объект был создан.


σ>А можно ссылку на стандарт, плес?


Нет, я не знаток стандарта. Но эмпирический опыт говорит именно об этом.

Если вы знаете, как создать объект без выполнения этих действий, то покажите как.

σ>Да может не один, только вот описание того, что делает start_lifetime_as, или про что там мы говорили, от числа (не)понимающих не зависит.


Ну так о том и речь, что описание start_lifetime_as из стандарта нужно перевести на нормальный язык, чтобы число понимающий было больше. Текст стандарта для этого плохо подходит.
Re[98]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 17:01
Оценка:
Здравствуйте, σ, Вы писали:

σ>Выше показано два куска кода про которые утверждается что у них эквивалентное поведение.


Выглядит как эквивалентное.

σ>Ток вот хорошо бы сначала поиметь описания поведения оригинального


Проссыте, но тема слишком большая чтобы искать оригинал. В чем принципиальные отличия от исходного оригинала или от упрощенного варианта с struct S? По сравнению с упрощенным я принципиальных отличий не вижу. Покажите пальцем, плиз.

S>>Если при этом есть какие-то нарушения стандарта, то хотелось бы об этом услышать.


σ>В свою очередь, хотелось бы увидеть описание поведения (с т.з. стандарта, естественно)


Напоминает зацикливание. Следовательно таким путем никуда не придем.
Re[105]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:07
Оценка:
S>>>Это типа обязательные действия для того, чтобы объект был создан.

σ>>А можно ссылку на стандарт, плес?


S>Нет, я не знаток стандарта. Но эмпирический опыт говорит именно об этом.


>эмпирический опыт

>о, как сам писал, софистике

Я даже не знаю что сказать
Re[102]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 17:13
Оценка:
Здравствуйте, σ, Вы писали:

σ>Дядя, с головой в порядке? Я вообще-то вопрос задавал (https://rsdn.org/forum/cpp/8581729.1
Автор: σ
Дата: 16.08.23
), как я в принципе мог, как вы выражаетесь, «обдристаться»?

σ>Или вы перепутали кто из нас не осилил описать «ожидаему логику»?

Что, я не слышу, что ты говоришь? Я слышу с твоей стороны только какие-то странные звуки... кажется это звук, как по твоим штанишкам текут жидкие какашки XDDD }:0]
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:17
Оценка:
σ>>Ток вот хорошо бы сначала поиметь описания поведения оригинального

S>Проссыте, но тема слишком большая чтобы искать оригинал. В чем принципиальные отличия от исходного оригинала или от упрощенного варианта с struct S? По сравнению с упрощенным я принципиальных отличий не вижу. Покажите пальцем, плиз.


Я предложил вместо кода из https://rsdn.org/forum/cpp/8581729.1
Автор: σ
Дата: 16.08.23
взять код попроще https://rsdn.org/forum/cpp/8585034.1
Автор: σ
Дата: 21.08.23
, чтобы не лезть в описание стандартной библиотеки из-за std::map. И описать поведение этого кода, если предположить, что NRVO.

S>>>Если при этом есть какие-то нарушения стандарта, то хотелось бы об этом услышать.


σ>>В свою очередь, хотелось бы увидеть описание поведения (с т.з. стандарта, естественно)


S>Напоминает зацикливание. Следовательно таким путем никуда не придем.


По-моему, никто (кроме меня) ещё не пытался даже начать описывать, одно невнятное мямленье про "эмпирический опыт" и "выглядит как", так что зацикливаться некуда.
Отредактировано 21.08.2023 17:22 σ . Предыдущая версия .
Re[106]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 17:18
Оценка:
Здравствуйте, σ, Вы писали:

S>>>>Это типа обязательные действия для того, чтобы объект был создан.


σ>>>А можно ссылку на стандарт, плес?


S>>Нет, я не знаток стандарта. Но эмпирический опыт говорит именно об этом.


>>эмпирический опыт

>>о, как сам писал, софистике

σ>Я даже не знаю что сказать


Приведите пример когда объект создается без выделения памяти под него и без присваивания ему значения (если мы говорим об объектах, а не о банальных int-ах). Этого будет достаточно.

А то у вас есть привычка на прямые вопросы и просьбы отвечать избирательно.
Re[94]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 17:21
Оценка:
Здравствуйте, σ, Вы писали:

V>>>>Согласно семантике — два.

σ>>>Да нет, согласно семантике — один.
V>>Два.
σ>Симптоматично, что ни одного пруфа от тебя до сих пор не было.

Чем исходник не пруф?


V>>В этом суть оптимизации.

V>>Точно такая же происходит здесь:
V>>
σ>const SomeObj obj = SomeObj(args);
σ>

V>>Согласно семантике, создаётся временный безымянный объект и копируется (либо перемещается) в целевую переменную obj.
σ>Или не создаётся и не копируется

А ты проверял?
class SomeObj {
public:
    SomeObj(int) {}
    //SomeObj(const SomeObj &) = delete;
};

//const SomeObj obj = SomeObj(42);
const SomeObj obj2(42);

Поиграй с раскомментированием строчек в различных сочетаниях.


σ>тоже «согласно семантике», а не «способу реализации»


Семантика описана простейшим исходником, который я ХЗ как можно было не суметь прочитать.

Если же ты опять пытаешься озвучить свою "эрудицию", то ты ошибся стадией рассуждения об исходнике — оптимизация выполняется над изначальной неоптимизированной моделью кода, и в этой модели кода должен быть доступен конструктор копирования, которого после оптимизации не будет. Но он всё-равно нужен.

Ну и, в дебаге обычно полное повторение описанного в коде безо-всякий оптимизаций.


V>>Лишнего копирования/перемещения можно избежать.

V>>При возврате по значению применяется ровно та же логика.
σ>Только при возврате по значению может быть несколько переменных с разной константностью

И какая разница, если оперируем данными по значению?
Семантически в этом случае создаются копии объектов.

А упоминание об обязательности RVO — это ж для дурачка-программиста, а не для компилятора, потому что с С++17 RVO будет использовано в любом случае, даже если конструкторы/деструкторы имеют побочные эффекты.

Выделенное — это для тебя, программиста, чтобы ты потом не задавал вопросов "а почему так?".
(Впрочем, в это уже тыкал, пошли по кругу)


σ>И тогда возникают некоторые вопросы.


Странные у тебя какие-то вопросы, которые ты не в состоянии даже просто сформулировать на 20-й итерации.


σ>Но даже если бы было и только — какая разница?


Никакой, бо оптимизация не изменяет семантику.

А даже если случилось RVO, то мы имеем дело с одной областью памяти, но с разными ссылками на неё в разные моменты работы программы, но никогда одновременно.
(Опять по кругу в тебя этим тыкают)

ХЗ, кароч...
Если сложно с пониманием передачи данных по значению, попробуй порассуждать про передачу через ссылочную семантику:
SomeObj * const obj = new SomeObj(42);

Тут оператор new создаёт в куче неконстантный объект и возвращает неконстантный указатель на этот объект, где значение неконстантного указателя копируется в константный указатель obj.

Надеюсь, хотя бы с примитивными типами данных сложности понимания не возникают — каким образом мы копируем числовое значение неконстантного указателя в константный? ))

А если обернуть числовое значение в некий класс SomeObj, ы?
Неужели понимать становится сложнее? ))
Отредактировано 21.08.2023 19:16 vdimas . Предыдущая версия . Еще …
Отредактировано 21.08.2023 17:23 vdimas . Предыдущая версия .
Re[94]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 21.08.23 17:21
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>Когда объект один в обоих местах, то он либо константный и там и там, либо не там и не там. Если он константный, то его модифицировать его в функции это UB. А если неконстантный, то его можно модифицировать вне функции, это не UB.


BFE>>(тихо хихикая) Т.е. согласно вашей логике, исходный пример

BFE>>
σ>std::map<int, int> buildMap() {
σ>    std::map<int, int> result;

σ>    result.insert(42, 43); 
σ>    ...
σ>    return result;
σ>}

σ>const std::map<int, int> someDictionary = buildMap();
σ>

BFE>>- это UB, если NRVO ?

σ>Может да. Может нет. Может на это сложно/невозможно ответить.

σ>Я об этом спросил у форумчан, но в ответ получил тонну истерики, и ни одной попытки описания поведения со ссылками на стандарт. ¯\_(ツ)_/¯

Последнее время ссылаться на стандарт становится дурным тоном, так как комитет занят безумной попыткой описать формальное поведение на естественном английском языке. Эта задача не выполнима, так как под каждое словесное описание придётся дополнительно писать толкование написанных слов. Дошло до того, что стандарт невозможно понять без proposal'ов. Это состояние усугубляется некоторыми деятелями, которые стремятся получить формально корректное описание вопреки заложенным намерениям. Собственно, см. subj.

BFE>>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?

σ>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.

О! Да неужели?! Вы, наконец-то, начали отличать тип переменной от типа объекта и тип объекта от самого объекта?! Ура!

Смотрите, функция buildMap() возвращает объект типа std::map<int, int>, а потом в выражении const std::map<int, int> someDictionary = buildMap(); этим ( полученным из функции buildMap() ) объектом инициализируется переменная someDictionary. NRVO — это про то, что возвращает функция, а не про инициализацию константного объекта обозначенного именем someDictionary. То, что потом случается сopy elision к самой функции отношения уже не имеет.

Если в стандарте описано что-то другое, то этот стандарт надо подправить, а не поведение менять.
И каждый день — без права на ошибку...
Re[100]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 17:24
Оценка:
Здравствуйте, σ, Вы писали:

S>>Проссыте, но тема слишком большая чтобы искать оригинал. В чем принципиальные отличия от исходного оригинала или от упрощенного варианта с struct S? По сравнению с упрощенным я принципиальных отличий не вижу. Покажите пальцем, плиз.


σ>Я предложил вместо кода из https://rsdn.org/forum/cpp/8581729.1
Автор: σ
Дата: 16.08.23
взять код попроще https://rsdn.org/forum/cpp/8585034.1
Автор: σ
Дата: 21.08.23
, чтобы не лезть в описание стандартной библиотеки из-за std::map. И описать поведение этого кода, если предположить, что NRVO.


OK, смотрим на исходный код:
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); // мутабельность
}

const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект

Здесь, кстати, в buildMap нет return-а. Опечатка, бывает.

Смотрим на тот код, который я преобразовал:
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

void useMap() {
    const std::map<int, int> someDictionary = buildMap();
    ...
}


Вот хоть убейте, но никаких существенных отличий между ними двумя не вижу. Так что нет причин откатываться вот прям к исходному оригиналу.

S>>>>Если при этом есть какие-то нарушения стандарта, то хотелось бы об этом услышать.


σ>>>В свою очередь, хотелось бы увидеть описание поведения (с т.з. стандарта, естественно)


S>>Напоминает зацикливание. Следовательно таким путем никуда не придем.


σ>По-моему, никто (кроме меня) ещё не пытался даже начать описывать, так что зацикливаться некуда.


Когда вас просят ответить предметно вы просите привести цитату. Снова и снова. Вот и зацикливание.
Re[98]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 17:26
Оценка:
Здравствуйте, σ, Вы писали:

TB>>Обоснуй что это УБ

σ>Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1

Пфф...
Похоже на инкарнацию шимжи.


σ>Если по семантике C++ это один и тот же объект


Нет никаких "если".
Не считает.
Re[107]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:27
Оценка:
S>Приведите пример когда объект создается без выделения памяти под него и без присваивания ему значения (если мы говорим об объектах, а не о банальных int-ах). Этого будет достаточно.

S>А то у вас есть привычка на прямые вопросы и просьбы отвечать избирательно.


Я вообще не понимаю с чего ты докопался до меня этим требованием тебе что-то показать про объекты без памяти. Что тебе показалось что я утверждал? Что ты пытаешься оспорить? Сформулируй внятно, плез.

S>если мы говорим об объектах, а не о банальных int-ах


Про это я вообще не понял. Объект типа int — не объект?
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 17:33
Оценка:
Здравствуйте, σ, Вы писали:

S>>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.

σ>И каким же образом объект вдруг поменяет свою константность?

Только не объект, а переменная.
Переменная и не меняет свою константность — это твои смешные фантазии.

Переменная как identity объекта становится доступной для использования только после инициализации объекта, поэтому "менять константность" не требуется.


S>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект

σ>this во время конструкции константного объекта указаывает, внезапно, на константный объект.

this указывает на неконстантный объект, в чём ты можешь легко убедиться.


S>>изменение состояния внутри конструктора через этот указатель никакое не UB.

σ>Потому что так написано в стандарте https://timsong-cpp.github.io/cppwp/n4868/class.ctor.general#5

И в чём твоя проблема?
Гугл-переводчик сломался?
RV-оптимизация происходит, на секундочку, над конструктором копирования.
Или это тебе не конструктор уже? ))
Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:34
Оценка:
S>OK, смотрим на исходный код:
S>
S>std::map<int, int> buildMap() {
S>    std::map<int, int> result;

S>    result.insert(42, 43); // мутабельность
S>}

S>const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект
S>

S>Здесь, кстати, в buildMap нет return-а. Опечатка, бывает.

S>Смотрим на тот код, который я преобразовал:

S>
S>std::map<int, int> buildMap() {
S>    std::map<int, int> result;

S>    result.insert(42, 43); 
S>    ...
S>    return result;
S>}

S>void useMap() {
S>    const std::map<int, int> someDictionary = buildMap();
S>    ...
S>}
S>


S>Вот хоть убейте, но никаких существенных отличий между ними двумя не вижу.


Бляааааааааааааааааааааааааааа
Я говорил, что прежде чем доказывать эквивалентность первого и второго кода в https://rsdn.org/forum/cpp/8585051.1
Автор: so5team
Дата: 21.08.23
, надо описать поведение первого кода. Только не "эмпирически".

А не про то, что засовывание const std::map<int, int> someDictionary = buildMap(); внутрь функции что-то принципиально поменяет

S>Когда вас просят ответить предметно вы просите привести цитату. Снова и снова. Вот и зацикливание.


Я предметно дохрена написал. В ответ получил про эмпирический опыт ощущения объектов, которые софистика, которая есть только на уровне стандарта.
Re[102]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 17:37
Оценка:
Здравствуйте, σ, Вы писали:

S> В ответ получил про эмпирический опыт ощущения объектов, которые софистика, которая есть только на уровне стандарта.


Кто тебе виноват, что ты не знаешь, что такое УБ на практике и как оно должно проявляться? Поэтому вместо нормального разговора тыкаешь в буквы, которые ты не понимаешь?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[94]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 17:41
Оценка:
Здравствуйте, σ, Вы писали:

σ>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта)


Опять хамишь, хотя сам же косячишь в рассуждениях.
Потом обижаешься на отлуп. ))

Если рассуждать "полностью корректно", то можно говорить только о типах данных, о данных соотв. типов и о переменных, где хранятся данные соотв. типов.

В общем, если хочешь получить технически грамотный ответ — спрашивай технически грамотно.

Если спрашиваешь "своими словами" аки брат Нибэнимеда — то тебе рукой и показывают, согласно демонстрируемого тобой уровня восприятия инфы.
Re[95]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:45
Оценка: :)
BFE>Последнее время ссылаться на стандарт становится дурным тоном, так как комитет занят безумной попыткой описать формальное поведение на естественном английском языке. Эта задача не выполнима, так как под каждое словесное описание придётся дополнительно писать толкование написанных слов. Дошло до того, что стандарт невозможно понять без proposal'ов. Это состояние усугубляется некоторыми деятелями, которые стремятся получить формально корректное описание вопреки заложенным намерениям. Собственно, см. subj.

Nice copium.

BFE>>>А ничего, что возвращаемый функцией buildMap() тип отличается от типа объекта someDictionary? Не смущает?

σ>>Сделай глубойкий вдох, убедись, что отличаешь переменные от объектов (и, следовательно, тип переменной от типа объекта), и попробуй сказать, какой же тип у объекта в случае NRVO, т.е. когда переменные result и someDictionary обозначают один и тот же объект.

BFE>О! Да неужели?! Вы, наконец-то, начали отличать тип переменной от типа объекта и тип объекта от самого объекта?! Ура!


Где ты видел, что я не отличаю?

BFE>Смотрите, функция buildMap() возвращает объект типа std::map<int, int>, а потом в выражении const std::map<int, int> someDictionary = buildMap(); этим ( полученным из функции buildMap() ) объектом инициализируется переменная someDictionary.


Не думаю, что это описание подходит для C++17 и выше. И ты отвечаешь не на то, про что я спросил. Видимо, тоже не понял, про что вопрос.

BFE>NRVO — это про то, что возвращает функция, а не про инициализацию константного объекта обозначенного именем someDictionary. То, что потом случается сopy elision к самой функции отношения уже не имеет.


В C++17 уже нет copy elision, ну да ладно, не суть важно.

Давай я тебе помогу выдать ответ на мой исходный вопрос. Задам два вопроса (речь про C++17+):

1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?
2. Если ответ на предыдущий вопрос утвердительный, то тогда: этот объект константный или нет? (Объяснить почему)

BFE>Если в стандарте описано что-то другое, то этот стандарт надо подправить, а не поведение менять.


Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 17:49
Оценка:
σ>>Если по семантике C++ это один и тот же объект

V>Нет никаких "если".

V>Не считает.

Очередной беспруфный вскукарек засчитан
Re[102]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 17:54
Оценка:
Здравствуйте, σ, Вы писали:

σ>Я говорил, что прежде чем доказывать эквивалентность первого и второго кода в https://rsdn.org/forum/cpp/8585051.1
Автор: so5team
Дата: 21.08.23
, надо описать поведение первого кода. Только не "эмпирически".


Ну так опишите. И первого, и второго. И найдите отличия. Как найдете можно будет обсудить. Если будет что, поскольку есть сомнения, что найдете.

σ>Я предметно дохрена написал.


Вам кажется. Цитата из стандарта про то, что такое константный объект -- это лишь цитата из стандарта.

В стандарте иногда описывали вещи, которые на практике не существовали.
И не описывали вещи, которыми широко пользовались, а потом пришлось добавлять туда std::launder, std::start_lifetime_as и т.д.
Re[97]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 21.08.23 17:57
Оценка:
Здравствуйте, so5team, Вы писали:

S>Я был бы признателен, если бы кто-нибудь объяснил откуда может взяться UB и вообще как результирующий константный объект может рассматриваться до завершения работы порождающей его функции.

UB может взяться, понятное дело, из стандарта. Если внутри стандарта есть противоречие или же неоднозначное прочтение, то вот и UB. Первый раз, что ли?

Конкретно по данному примеру, если подходить формально, то после всех оптимизаций должен создаваться ровно один объект. Константный объект, который нельзя менять и который изменяется после своего создания. Чтобы проверить, есть тут формальное UB или нет, надо половину стандарта прочитать и простить понять. При этом надо нигде не ошибиться в том, что авторы понимали под теми словами, что написали.

И да, формально может оказаться, что вообще константный объект не может быть создан, если у него конструктор нетривиальный.
И каждый день — без права на ошибку...
Re[96]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 17:57
Оценка:
Здравствуйте, vopl, Вы писали:

V>представленная развертка существенно не эквивалентна исходнику


Эквивалентна


V>в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>


Верно.


V>в развертке же это имя означает ссылку


Да, можно было другое имя для ссылки взять. ))

const std::map<int, int> someDictionary = buildMap();
const std::map<int, int> & someDictionaryRef = someDictionary;


Если затем ссылаться на map только через someDictionaryRef — получим полную идентичность до совпадений даже имён (если уж к именам придрался).


V>и применяемый тип относится к ссылке но не к объекту


Ссылка на объект может быть интерпретирована как неотличимая от объекта — это почему компилятор не обязан заводить переменную-ссылку в памяти, если он "видит" её инициализацию, и это прямо по стандарту.

То бишь, хотя в примере выше у нас две переменные, на стеке будет выделено место только для первой из них, а ссылка someDictionaryRef будет использоваться сугубо как алиас имени someDictionary.

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


V>при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный


Не "уже не константный", а "еще не константный"


V>таким образом, гипотетическое UB из исходника никак не возможно в развертке так как объект перестал быть константным


Гипотетическое UB невозможно в обоих случаях, т.к. оба случая полностью эквивалентны.

Развёртка показала последовательность происходящего, где константное ссылание на объект возможно только после того, как закончилось мутирование объекта.
После инициализации константной ссылки никакое мутирование не происходит, значит нет и UB.
Re[100]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 18:03
Оценка: +1
Здравствуйте, σ, Вы писали:

σ>>>Ты тролль или дурачок? https://timsong-cpp.github.io/cppwp/n4868/dcl.type.cv#4.sentence-1


S>>Только вот фишка в том, что до выхода из функции нет никакого константного объекта. Он появляется только когда функция закончилась.


σ>Это когда нет NRVO. (И то, скорее константный объект появляется всё-таки до вызова функции, а его инициализация заканчивается (и, следовательно, лайфтайм начинается) после вызова. Ну это так, детали, хер с ними).


До вызова функции может появится разве что место под объект.

σ>А если есть NRVO, то теперь переменная вне функции и внутри, вместо обозначения двух разных объектов, начинают обозначать один и тот же. Я выше кидал цитату про two different ways of referring to the same object.


Еще раз: переменной вне нет пока порождающая функция не завершилась. Место под переменную есть, переменной нет.

S>>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.


σ>И каким же образом объект вдруг поменяет свою константность?


Не поменяет, а приобретет. Точно так же, как объект приобретает константность после завершения его инициализации.

S>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект


σ>this во время конструкции константного объекта указаывает, внезапно, на константный объект.


А тот факт, что якобы константный объект можно менять, вам жить не мешает? Или эмпирический опыт вы отвергаете как класс?

S>>изменение состояния внутри конструктора через этот указатель никакое не UB.


σ>Потому что так написано в стандарте https://timsong-cpp.github.io/cppwp/n4868/class.ctor.general#5


Ну так там же и написано, что const на время работы конструктора на объект не распространяется. Т.е. пока инициализация не завершилась нет никакого константного объекта.
Re[103]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 18:07
Оценка:
σ>>Я говорил, что прежде чем доказывать эквивалентность первого и второго кода в https://rsdn.org/forum/cpp/8585051.1
Автор: so5team
Дата: 21.08.23
, надо описать поведение первого кода. Только не "эмпирически".


S>Ну так опишите. И первого, и второго. И найдите отличия. Как найдете можно будет обсудить. Если будет что, поскольку есть сомнения, что найдете.


Вроде всё началось с того, что я задал вопрос про константность объекта. Это часть описания. Т.е. у меня как бы вопрос как правильно описать.
Зачем ты мне на это пишешь
S>Ну так опишите

Ты же понимаешь, что это в принципе неправильно?
Нет ответа, ну, иди мимо

σ>>Я предметно дохрена написал.


S>Вам кажется. Цитата из стандарта про то, что такое константный объект -- это лишь цитата из стандарта.


S>В стандарте иногда описывали вещи, которые на практике не существовали.

S>И не описывали вещи, которыми широко пользовались, а потом пришлось добавлять туда std::launder, std::start_lifetime_as и т.д.

Ты уже докатился почти что до резонёрства.
Re[97]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 18:07
Оценка: -2 :)
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>представленная развертка существенно не эквивалентна исходнику, в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>

V>>в развертке же это имя означает ссылку, и применяемый тип относится к ссылке но не к объекту, при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный

S>Простите за грубость

ничего страшного, прощаю

S>, но когда вы в исходном коде видите:

S>
S>const std::map<int, int> someName;
S>

S>то кто вам гарантирует, что идентификатор someName означает что-то кроме ссылки после прохода оптимизатора?

похоже, мы разговариваем на разных языках.. Причем тут оптимизатор — категорически не понимаю. Есть язык, у него есть некие эталонные правила — стандарт. Исходный замес бы исключительно возле этого аспекта. Оптимизатор, линкер, та-или-иная реализация компилятора и прочий тул — это все конечно имеет место быть, но к теме не относится.

Непосредственно в приведенном кусочке — объявляется имя someName и означаемый им объект, этот oбъект имеет тип const std::map<int, int>. Никаких ссылок тут нет. Чтобы работать со ссылками нужно явно использовать ссылочный тип, например так
const std::map<int, int>& someName = blabla;


S> И вообще хоть что-то да значит?


V>>таким образом, гипотетическое UB из исходника никак не возможно в развертке так как объект перестал быть константным


S>Я был бы признателен, если бы кто-нибудь объяснил откуда может взяться UB и вообще как результирующий константный объект может рассматриваться до завершения работы порождающей его функции.


тут
Автор: σ
Дата: 21.08.23
приводился пример, продублирую
struct S { int i; };

S f()
{
  S s;

  s.i = 0; // гипотетическое UB тут

  return s; // NRVO
}

const S t = f(); // NRVO


почему тут подозревается UB:
1. имеем NRVO, а в этом случае возвращаемый из функции объект и объект внитри функции — это один и тот же объект (ссылку выше приводил ув. σ)
2. тип объекта определяется по декларации этого объекта. Имеем две декларации, во второй объект имеет константный тип, следовательно, компилятор вполне может его (объект) трактовать как константный
3. следовательно, объект, обозначенный именем s (который в силу NRVO есть тот же самый что и t) — можеть быть оттрактован компилятором как константный
4. модификация полей константного объекта — UB (ссылку выше приводил ув. σ)
5. следовательно, модификация s.i = 0 подозревается в UB


S>А еще было бы круто если бы кто-нибудь из почитателей святой буквы стандарта


зачем ерничать? Я постараюсь ответить на все моменты по сабжу если это будет в моих силах, но только чтобы это все происходило в инженерном ключе а не в эмоциональном

S> наконец-то объяснил простую штуку:

S>
S>class demo {
S>  int i_;
S>public:
S>  demo() {
S>    i_ = f();
S>  }
S>  int f() { return rand(); }
S>};

S>const demo d;
S>

S>работает конструктор константного объекта, но сам объект в это время нифига не константа.

ув. σ выше по теме приводил норму для этого случая, лень искать. Вкратце простыми словами — конструктору в этом случае дадено исключительное право сцецифическим образом плевать на константность.

S>А то доказывать, что термин "implicitly creates" понятен всем и каждому, вот прям горазды.


Лично я когда зашел в тему — вообще не задумывался ни про какие там "implicitly creates", вообще слова такого даже не знал. Ув. σ его употребил — я пошел в стандарте посмотреть что оно означает, почитал-ознакомился, оказалось это вполне четкая штуковина. То есть, "понятен всем и каждому" — лично мне небыло ничего понятно.

S>А ответить на простые вопросы так "покажите мне текст стандарта".

и судя по всему это правильно. Именно стандарт и определяет все эти аспекты поведения, с него и надо начинать
Re[97]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 18:09
Оценка:
Здравствуйте, so5team, Вы писали:

S>А то доказывать, что термин "implicitly creates" понятен всем и каждому, вот прям горазды. А ответить на простые вопросы так "покажите мне текст стандарта".


Можно отсылать прямо в home стандарта, в рекомендуемое предисловие к материалу:
https://isocpp.org/tour

И там примерно такое (гуглоперевод):

Предисловие к Языку программирования C++, 4-е изд.

Эта книга предназначена для трех аудиторий:

Программисты C++, которые хотят знать, что предлагает последний стандарт ISO C++,
Программисты на C, которым интересно, что C++ предлагает помимо C, и
Люди, имеющие опыт работы с языками приложений, такими как Java, C#, Python и Ruby, которые ищут что-то «ближе к машине» — что-то более гибкое, что-то с лучшей проверкой во время компиляции или что-то с большей производительностью.

Естественно, эти три группы не являются непересекающимися — профессиональный разработчик программного обеспечения владеет более чем одним языком программирования.

Эта книга предполагает, что ее читатели — программисты. Если вы спросите: «Что такое цикл for?» или «Что такое компилятор?» тогда эта книга (пока) не для вас; вместо этого я рекомендую книгу Programming: Principles and Practice Using C++ , чтобы начать работу с программированием на C++. Кроме того, я предполагаю, что читатели уже достигли определенной зрелости как разработчики программного обеспечения. Если вы спросите: «Зачем вообще тестировать?» или сказать: «Все языки в основном одинаковы; просто покажите мне синтаксис» или уверены, что существует единственный язык, идеально подходящий для любой задачи, эта книга не для вас.

Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 18:11
Оценка:
S>>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект
σ>>this во время конструкции константного объекта указаывает, внезапно, на константный объект.

V>this указывает на неконстантный объект, в чём ты можешь легко убедиться.


this указывает на константный объект, в чём ты можешь легко убедиться.

S>>>изменение состояния внутри конструктора через этот указатель никакое не UB.

σ>>Потому что так написано в стандарте https://timsong-cpp.github.io/cppwp/n4868/class.ctor.general#5

V>И в чём твоя проблема?

V>Гугл-переводчик сломался?
V>RV-оптимизация происходит, на секундочку, над конструктором копирования.
V>Или это тебе не конструктор уже? ))

Ты, походу, уже совсем почти бессвязную белеберду выдаёшь.
Re[96]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 21.08.23 18:20
Оценка: +1
Здравствуйте, σ, Вы писали:

σ>Nice copium.

Комитета.

σ>Не думаю, что это описание подходит для C++17 и выше. И ты отвечаешь не на то, про что я спросил. Видимо, тоже не понял, про что вопрос.

Я понял, что вы спросили. Вы не поняли моего ответа.

BFE>>NRVO — это про то, что возвращает функция, а не про инициализацию константного объекта обозначенного именем someDictionary. То, что потом случается сopy elision к самой функции отношения уже не имеет.

σ>В C++17 уже нет copy elision, ну да ладно, не суть важно.
Да, я знаю, что после C++17 всё это сильно запутали. Стало хуже.

σ>Давай я тебе помогу выдать ответ на мой исходный вопрос.

Лучше скажите, вот в этом коде:
struct A
{
  int m{}; 
  A() { m = 1; }
}

const A a;

константный объект a меняется во время своей инициализации. А ведь это UB — константный объект менять нельзя!
σ>Задам два вопроса (речь про C++17+):
σ>1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?
σ>2. Если ответ на предыдущий вопрос утвердительный, то тогда: этот объект константный или нет? (Объяснить почему)

Давайте я вам подсказку дам, где вы ошибаетесь. Вот она: lifetime
И каждый день — без права на ошибку...
Re[98]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 18:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>И да, формально может оказаться, что вообще константный объект не может быть создан, если у него конструктор нетривиальный.


Ну да, докатиться можно и до этого в рассуждениях. ))

Но тут простой ответ в том, что ссылку на такой объект можно получить только после завершения конструирования, кроме как в случае глобальных переменных, о чём было сказано cразу же.
Re[98]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 18:22
Оценка:
Здравствуйте, vopl, Вы писали:

V>тут
Автор: σ
Дата: 21.08.23
приводился пример, продублирую

V>
V>struct S { int i; };

V>S f()
V>{
V>  S s;

V>  s.i = 0; // гипотетическое UB тут

V>  return s; // NRVO
V>}

V>const S t = f(); // NRVO
V>


Брат по разуму что ли?
Если тут якобы есть UB, то как мы можем пронаблюдать это самое UB? Покажи развёрнутый пример, который выдаёт разный результат в дебаге и релизе.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[102]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 18:24
Оценка:
Здравствуйте, σ, Вы писали:

σ>this указывает на константный объект, в чём ты можешь легко убедиться.


Ты хоть раз в жизни собирал и запускал программу, написанную тобой на С++?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[95]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 18:33
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Смотрите, функция buildMap() возвращает объект типа std::map<int, int>, а потом в выражении const std::map<int, int> someDictionary = buildMap(); этим ( полученным из функции buildMap() ) объектом инициализируется переменная someDictionary.


Да, сopy elision там возникает дважды — при возврате значения из ф-ии и при конструировании целевой переменной.


BFE>NRVO — это про то, что возвращает функция, а не про инициализацию константного объекта обозначенного именем someDictionary.


Семантически да, ф-ия возвращает безымянный неконстантный объект, который является аргументом конструктора копирования при инициализации константной переменной.


BFE>То, что потом случается сopy elision к самой функции отношения уже не имеет.


Но ф-ия могла бы возвращать сразу const std::map<int, int>, и все рассуждения выше по ветке были бы верны.
Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 18:40
Оценка: -1
σ>>А если есть NRVO, то теперь переменная вне функции и внутри, вместо обозначения двух разных объектов, начинают обозначать один и тот же. Я выше кидал цитату про two different ways of referring to the same object.

S>Еще раз: переменной вне нет пока порождающая функция не завершилась. Место под переменную есть, переменной нет.


Какое ещё место под переменную? Ты случайно не путаешь переменные и объекты?

S>>>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.


σ>>И каким же образом объект вдруг поменяет свою константность?


S>Не поменяет, а приобретет.


Ладно, спрошу как тебе угодно: каким образом приобретёт.

S>Точно так же, как объект приобретает константность после завершения его инициализации.


Т.е. никак?

S>>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект


σ>>this во время конструкции константного объекта указаывает, внезапно, на константный объект.


S>А тот факт, что якобы константный объект можно менять, вам жить не мешает?


Нет. Возможно, у тебя при словах "константный объект" возникают какие-то необоснованные ассоциации/представления, то кто тебе виноват?

S>Или эмпирический опыт вы отвергаете как класс?


Байден пожимает невидимые руки рынка, а у тебя вместо этого эмпирический опыт константных объектов?

S>>>изменение состояния внутри конструктора через этот указатель никакое не UB.


σ>>Потому что так написано в стандарте https://timsong-cpp.github.io/cppwp/n4868/class.ctor.general#5


S>Ну так там же и написано, что const на время работы конструктора на объект не распространяется.


Написано, что const semantics не распространяется.

S>Т.е. пока инициализация не завершилась нет никакого константного объекта.


а что инициализируем тогда?

Хм, а, кстати, в упрощённом коде:
struct S { int i; };

S f()
{
  S s;

  s.i = 0;
}

const S t = f();

Если применяется NRVO, и тогда переменные s и t обозначают один и тот же объект, то по-твоему
1. Инициализация для этого объекта заканчивается в S s;?
2. Или заканчивается только после возвращения из функции, и значит внутри он — неинициализированный (и, следовательно, его lifetime ещё не начался, и, следовательно, обращаться к его членам — UB)?
Re[99]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 18:41
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, vopl, Вы писали:


V>>тут
Автор: σ
Дата: 21.08.23
приводился пример, продублирую

V>>
V>>struct S { int i; };

V>>S f()
V>>{
V>>  S s;

V>>  s.i = 0; // гипотетическое UB тут

V>>  return s; // NRVO
V>>}

V>>const S t = f(); // NRVO
V>>


TB>Брат по разуму что ли?

хамство лучше не надо применять, нет причин

TB>Если тут якобы есть UB, то как мы можем пронаблюдать это самое UB? Покажи развёрнутый пример, который выдаёт разный результат в дебаге и релизе.


Во первых, не вижу необходимости кому либо что то демонстрироать. Обрати внимание, я называю сабжевое UB "гипотетическим", "подозреваемым".
Во вторых, это так не работает. Наличие UB не гарантирует наличие аномалий, лишь только делает их возможными, то есть, из наличия UB не следует обязательное наличие аномалий.
В третьих, приведенная мной трактовка носит исключительно теоретический характер на текущий момент. Я просто сопостовляю положения стандарта, и из такого сопоставления вытекает возможность UB
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 18:47
Оценка: :)
BFE>>>NRVO — это про то, что возвращает функция, а не про инициализацию константного объекта обозначенного именем someDictionary. То, что потом случается сopy elision к самой функции отношения уже не имеет.
σ>>В C++17 уже нет copy elision, ну да ладно, не суть важно.
BFE>Да, я знаю, что после C++17 всё это сильно запутали. Стало хуже.
Смотря в чём. Концептуально стало значительно проще, а значит — лучше. То, что появились некоторые… дефекты. Ну, бывает.

σ>>Давай я тебе помогу выдать ответ на мой исходный вопрос.

BFE>Лучше скажите, вот в этом коде:
BFE>
struct A
{
  int m{}; 
  A() { m = 1; }
}

const A a;

BFE>константный объект a меняется во время своей инициализации.

Здесь вообще нет модификации a.

BFE> А ведь это UB — константный объект менять нельзя!


Про период конструкции и константные объекты я уже давал цитату.

σ>>Задам два вопроса (речь про C++17+):

σ>>1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?
σ>>2. Если ответ на предыдущий вопрос утвердительный, то тогда: этот объект константный или нет? (Объяснить почему)

BFE>Давайте я вам подсказку дам, где вы ошибаетесь. Вот она: lifetime


И что «lifetime»? Он начинается внутри функции, после инициализации result.
Re[96]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 18:49
Оценка:
Здравствуйте, σ, Вы писали:

σ>1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?


Не одновременно, и этого достаточно.

Ты бы оперировал полностью подробностями:
— на вызываемой стороне подготавливается область памяти для будущего объекта;
— ссылка на эту область передаётся для RVO в виде неявного аргумента;
— типы конструируемого и целевого объекта связаны весьма опосредовано — эти типы могут отличаться не только в константности;
— "внешняя" ссылка становится валидной строго после того, как "внутренняя" ссылка станет невалидной.


σ>2. Если ответ на предыдущий вопрос утвердительный


Отрицательный в такой постановке, бо ты исключаешь из вопроса время жизни переменных.


σ>то тогда: этот объект константный или нет? (Объяснить почему)


Потому что тебе уже говорили по кругу много раз, а до тебя не доходит. ))

Объект в конструкторе еще "никакой", его еще не существует.
Рассматривать целевую область памяти как объект можно только по завершении инициализации.
Re[100]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 18:50
Оценка:
Здравствуйте, vopl, Вы писали:

V>хамство лучше не надо применять, нет причин


Почему? Вижу балабола — хамлю.

V>Во вторых, это так не работает. Наличие UB не гарантирует наличие аномалий, лишь только делает их возможными, то есть, из наличия UB не следует обязательное наличие аномалий.


Тогда назови гипотетическую осмысленную оптимизацию, которая может быть возможно благодаря этому UB
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[102]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 18:52
Оценка:
Здравствуйте, σ, Вы писали:

σ>this указывает на константный объект, в чём ты можешь легко убедиться.

#include <stdio.h>
#include <stdlib.h>

class T {
    public: 
    void foo() { printf("foo()\n"); }
    void foo() const { printf("foo() const\n"); }
    T() {
        foo();
    }
};

int main() {
    const T t{};
    t.foo();
    return 0;
}

Угадай, что выведет?
Чтоб ИДЕ не открывать, я вот тут запустил: https://cplayground.com/?p=snail-mallard-tarsier
foo()
foo() const

Внутри конструктора зис — не конст. Понимаешь, вот это — пруф, а не твоё балабольство и размахивание руками.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[92]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 18:56
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>И во время конструирования в твоём примере объект тоже константный.

V>>Каким образом? ))
σ>По определению, которое я линканул.

Ты на вопрос не ответил.


σ>Его ты, видимо, тоже не смог понять


Так нечего понимать — ты не даёшь строгих определений, не спрашиваешь точные вопросы.


V>>Конструктор объекта не имеет понятия — создаёт ли он константный объект или мутабельный.

σ>И? Константный объект или нет зависит от его типа.

От модификатора переменной/выражения.
У тебя нет возможности описать константный пользовательский тип. ))


σ>А не от того, что там понимает конструктор.


Это согласно твоим забавным представлениям, где у тебя объект почему-то уже существует, когда его еще не существует.

Согласно определениям, принятым в С++, "объект" — это экземпляр "класса".
Пока нет готового экземпляра, нет объекта, ферштейн?

До тебя эту примитивщину не могут донести уже пол-сотни постов.


σ>Объект вообще может не конструктором инициализироваться.


Тогда он не лежит в своей объектной переменной и рассуждения о его первородной константности идут лесом.

Чего тут смешного — ты предлагаешь создавать объекты через UB, чтобы "доказать" другое UB.
Идиотизм на марше.


σ>Ты очень много пишешь всяких утверждений, которые вообще непонятно на что влияют.


Да тебе много чего не понятно.
Суть твоего торможения была понятна сразу — ты рассуждал о двух ссылках как о якобы пересекающихся по времени жизни.
Я сразу обратил на эту ошибку рассуждений твоё внимание.
Но ты облажался, не поняв сие важное замечание (или просто не обратив достаточное внимание).
Ну и всё.
После этого ты уже классический мальчик для битья, извини. ))
Сам напросился.


σ>Ты просто любишь своими наблюдениями делиться?


Да просто упоротых не жалко от слова совсем.
Вы выходите за границы разумного.

Вовсе не является недостатком незнание или непонимание чего либо, особенно при наличии желания узнать/понять.
Недостатком является лень ума и присущая этой лени упоротость.

Это как протест двоечников против невыученных уроков. ))
Неконструктив там целенаправленный, а не случайный.

Т.е. именно из-за намеренности созданного неконструктива упоротых можно и нужно тщательно пинать.
Вживую если — можно даже ногами по лицу. ))
Отредактировано 21.08.2023 19:10 vdimas . Предыдущая версия . Еще …
Отредактировано 21.08.2023 19:09 vdimas . Предыдущая версия .
Re[97]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 18:59
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>представленная развертка существенно не эквивалентна исходнику


V>Эквивалентна



V>>в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>


V>Верно.



V>>в развертке же это имя означает ссылку


V>Да, можно было другое имя для ссылки взять. ))

V>

V>const std::map<int, int> someDictionary = buildMap();
V>const std::map<int, int> & someDictionaryRef = someDictionary;


V>Если затем ссылаться на map только через someDictionaryRef — получим полную идентичность до совпадений даже имён (если уж к именам придрался).


вот тут внимательно посмотри
в исходном примере имеем const std::map<int, int> someDictionary = buildMap();
в развертке же ссылка

без эмоций подумай эту разницу. Конкретнее — в исходном случае получаем NRVO, а следовательно получаем и ситуацию с двумя декларациями одного и того же объекта, одну внутри функции вторую снаружи. И одна из них делает объект константным. Один и тот же объект. Внимательно присмотрись, без предубеждений
Re[97]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 19:06
Оценка:
σ>>1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?

V>Не одновременно, и этого достаточно.


Чё ты цепляешься за это "не одновременно" как за соломинку? "Не одновременно" это ты про то, что инициализируемая константная переменная вне области видимости тела функции? Тоже мне, проблема:
struct S { int i; };

S f();

const S t = f();

S f()
{
  S s;

  s.i = 0;

  return s;
}


V>Ты бы оперировал полностью подробностями:


Ты подробностями называешь детали реализации? Нахер ими вообще оперировать, рассуждая о семантике C++, можешь объяснить сперва? Семантика C++ не зависит от того, подготавливается там область памяти, или область хуямяти, или программа с бумажкой и карандашом интерпретируется.
Отредактировано 21.08.2023 19:20 σ . Предыдущая версия .
Re[97]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 19:07
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>представленная развертка существенно не эквивалентна исходнику


V>Эквивалентна



V>>в исходном варианте имя someDictionary означает объект, и тип этого объекта const std::map<int, int>


V>Верно.



V>>в развертке же это имя означает ссылку


V>Да, можно было другое имя для ссылки взять. ))

V>

V>const std::map<int, int> someDictionary = buildMap();
V>const std::map<int, int> & someDictionaryRef = someDictionary;


V>Если затем ссылаться на map только через someDictionaryRef — получим полную идентичность до совпадений даже имён (если уж к именам придрался).



V>>и применяемый тип относится к ссылке но не к объекту


V>Ссылка на объект может быть интерпретирована как неотличимая от объекта — это почему компилятор не обязан заводить переменную-ссылку в памяти, если он "видит" её инициализацию, и это прямо по стандарту.


V>То бишь, хотя в примере выше у нас две переменные, на стеке будет выделено место только для первой из них, а ссылка someDictionaryRef будет использоваться сугубо как алиас имени someDictionary.


V>(то же самое касается ссылок, инициализированных другими ссылками — они часто "схлопываются" в один алиас времени компиляции)



V>>при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный


V>Не "уже не константный", а "еще не константный"


Имено "уже не константный". В исходном примере он был константный, а потом ув. so5team его развернул и объект стал не костантным.
Re[98]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 19:10
Оценка: +1
Здравствуйте, vopl, Вы писали:

S>>, но когда вы в исходном коде видите:

S>>
S>>const std::map<int, int> someName;
S>>

S>>то кто вам гарантирует, что идентификатор someName означает что-то кроме ссылки после прохода оптимизатора?

V>похоже, мы разговариваем на разных языках.. Причем тут оптимизатор — категорически не понимаю.


Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.
Т.е., если мы изначально допускаем, что оптимизатор может пустить вдоль побочные эффекты конструкторов/деструкторов, то нелогично как-то требовать что someName после оптимизации означает тоже самое что и до.

V>почему тут подозревается UB:


Я, например, не понимаю, почему подозревается UB. Выглядит все это так: "мне кажется, что здесь UB, а вы мне покажите цитата из стандарта, чтобы мне казалось еще сильнее".

S>>А еще было бы круто если бы кто-нибудь из почитателей святой буквы стандарта


V>зачем ерничать?


Затем, что если бы мне сразу ответили на этот вопрос, то мы бы не ушли от тех самых контекстов, в которых объект то константа, то нет. Эта ложка оказалась бы к обеду.

V>ув. σ выше по теме приводил норму для этого случая, лень искать. Вкратце простыми словами — конструктору в этом случае дадено исключительное право сцецифическим образом плевать на константность.


Почему тоже самое не дано NRVO оптимизации? Если оно уже в одном месте так работает.

S>>А ответить на простые вопросы так "покажите мне текст стандарта".

V>и судя по всему это правильно. Именно стандарт и определяет все эти аспекты поведения, с него и надо начинать

Повторю еще раз: стандарт написан для специфической аудитории специфическим языком. То, что язык делает и как должно просто и понятно описываться другими словами для простых разработчиков. Поэтому если кому-то удобно оперировать термином implicitly creates, то это отрадно, но сомнительно что эта терминология будет удобна для большинства.
Re[98]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 19:11
Оценка:
Здравствуйте, vopl, Вы писали:

V>>Не "уже не константный", а "еще не константный"


V>Имено "уже не константный". В исходном примере он был константный, а потом ув. so5team его развернул и объект стал не костантным.


А вы докажите, что он не константный, т.к. единственный способ работы с ним -- это через константную ссылку. С которой константность снять вам никто не даст.
Re[93]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 19:16
Оценка: +1 :)
σ>>>>И во время конструирования в твоём примере объект тоже константный.
V>>>Каким образом? ))
σ>>По определению, которое я линканул.

V>Ты на вопрос не ответил.


Конструируя объект типа const T, конструируем константный объект, т.к. по определению объект типа const T это константный объект (const object). Вот определение: https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const.
Могу даже скопировать определение сюда
> A const object is an object of type const T

Охренеть как сложно, да?

σ>>Его ты, видимо, тоже не смог понять


V>Так нечего понимать — ты не даёшь строгих определений


Вот определение, даю в третий, если не больше, раз: https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const. Строже него нет.
Отредактировано 21.08.2023 19:19 σ . Предыдущая версия .
Re[102]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 21.08.23 19:20
Оценка: +1
Здравствуйте, σ, Вы писали:

S>>Еще раз: переменной вне нет пока порождающая функция не завершилась. Место под переменную есть, переменной нет.


σ>Какое ещё место под переменную? Ты случайно не путаешь переменные и объекты?


Ok, очепятался. Место под объект есть, объекта нет.

S>>>>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.


σ>>>И каким же образом объект вдруг поменяет свою константность?


S>>Не поменяет, а приобретет.


σ>Ладно, спрошу как тебе угодно: каким образом приобретёт.


Автоматически после завершения работы конструктора.

S>>Точно так же, как объект приобретает константность после завершения его инициализации.


σ>Т.е. никак?


Автоматически после завершения работы конструктора.

S>>>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект


σ>>>this во время конструкции константного объекта указаывает, внезапно, на константный объект.


S>>А тот факт, что якобы константный объект можно менять, вам жить не мешает?


σ>Нет. Возможно, у тебя при словах "константный объект" возникают какие-то необоснованные ассоциации/представления, то кто тебе виноват?


У меня простая ассоциация: константный объект менять нельзя. Это совпадает с тем, что я вижу в языке.
Соответственно, если объект можно менять, значит он неконстантный.

S>>Или эмпирический опыт вы отвергаете как класс?


σ>Байден пожимает невидимые руки рынка, а у тебя вместо этого эмпирический опыт константных объектов?


Да, несколько десятилетий пользуюсь ими. Есть опыт того, что с ними можно делать, а что нельзя. Менять, например, нельзя. mutable оставляем за бортом разговора.

S>>Ну так там же и написано, что const на время работы конструктора на объект не распространяется.


σ>Написано, что const semantics не распространяется.


И чтобы это могло значить? Ну, кроме того, что объект не константен.

S>>Т.е. пока инициализация не завершилась нет никакого константного объекта.


σ> а что инициализируем тогда?


Объект. Который затем станет константой.

σ>Если применяется NRVO, и тогда переменные s и t обозначают один и тот же объект, то по-твоему

σ>1. Инициализация для этого объекта заканчивается в S s;?
σ>2. Или заканчивается только после возвращения из функции, и значит внутри он — неинициализированный (и, следовательно, его lifetime ещё не начался, и, следовательно, обращаться к его членам — UB)?

По моему, здесь следует видеть два объекта:

* s внутри f() неконстантный;
* t вне f() константный.

Поскольку одновременно они не сущуствуют и использоваться одновременно не могут, то тот факт, что они являются одним объектом с точки зрения одной конкретной оптимизации -- это просто мелкая деталь реализации, не более того. Знать про которую разработчику нужно лишь для того, чтобы понять, куда подевались побочные эффекты из конструктора/деструктора.
Re[99]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 21.08.23 19:49
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


S>>>, но когда вы в исходном коде видите:

S>>>
S>>>const std::map<int, int> someName;
S>>>

S>>>то кто вам гарантирует, что идентификатор someName означает что-то кроме ссылки после прохода оптимизатора?

V>>похоже, мы разговариваем на разных языках.. Причем тут оптимизатор — категорически не понимаю.


S>Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.


аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


S>Т.е., если мы изначально допускаем, что оптимизатор может пустить вдоль побочные эффекты конструкторов/деструкторов, то нелогично как-то требовать что someName после оптимизации означает тоже самое что и до.


V>>почему тут подозревается UB:


S>Я, например, не понимаю, почему подозревается UB. Выглядит все это так: "мне кажется, что здесь UB, а вы мне покажите цитата из стандарта, чтобы мне казалось еще сильнее".


Выше приводил конкретные 5 пунктов, даже с косвенной отсылкой на стандарт, посредством которых мною допускается гипотеза сабжевого UB. То есть, те 5 пунктов объясняют, каким образом допускается гипотеза про UB. Я не просил никаких ссылок на стандарт, наоборот, готов предоставить их явно для обоснования тех или иных своих тезисов. На счет того что "мне кажется" — тут да, мне действительно кажется что здесь может быть оттрактовано UB, и приведенные выше 5 пунктов объясняют каким именно образом.

S>>>А еще было бы круто если бы кто-нибудь из почитателей святой буквы стандарта


V>>зачем ерничать?


S>Затем, что если бы мне сразу ответили на этот вопрос, то мы бы не ушли от тех самых контекстов, в которых объект то константа, то нет. Эта ложка оказалась бы к обеду.


Ерничание как штатный инструмент ведения беседы — это жесть. Я стараюсь отвечать на все заданные мне вопросы. Не припомню чтобы в твою сторону что то осталось без ответа.

V>>ув. σ выше по теме приводил норму для этого случая, лень искать. Вкратце простыми словами — конструктору в этом случае дадено исключительное право сцецифическим образом плевать на константность.


S>Почему тоже самое не дано NRVO оптимизации? Если оно уже в одном месте так работает.


Хороший вопрос, вряд ли я на него смогу ответить. Вероятно, это недоработка языка. Примерно такая же, что и привела к сабжевому гипотетическому UB — стандарт определил:
1. что тип объекта определяется его декларацией
2. модифицировать константный объект — UB
3. и тут добавили положение про NRVO, которое сделало возможным один и тот же объект задекларировать два раза, причем по разному (с константностью и без). И вот этот третий пункт с учетом предыдущих двух формирует всю обсуждаемую в текущей подветке котовасию


S>>>А ответить на простые вопросы так "покажите мне текст стандарта".

V>>и судя по всему это правильно. Именно стандарт и определяет все эти аспекты поведения, с него и надо начинать

S>Повторю еще раз: стандарт написан для специфической аудитории специфическим языком. То, что язык делает и как должно просто и понятно описываться другими словами для простых разработчиков. Поэтому если кому-то удобно оперировать термином implicitly creates, то это отрадно, но сомнительно что эта терминология будет удобна для большинства.


Это дело вкуса. Для меня, например, стандарт — это правила игры в язык C++. Если кто то хочет играть в игру на основе собственного понимания правил — пожалуйста, но стандарт — это источник первичного смысла в ней. Аналогично можно было бы сказать, что законы написаны для юристов, а потом недоумевать, почему мне штрафы сыпятся и почему меня в тюрьму сажают.
Re[103]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 19:57
Оценка: :)
S>>>>>Так что UB будет только если мы попробуем поменять константный объект уже после завершения функции из которого мы объект вернули. Но не до того как.

σ>>>>И каким же образом объект вдруг поменяет свою константность?


S>>>Не поменяет, а приобретет.


σ>>Ладно, спрошу как тебе угодно: каким образом приобретёт.


S>Автоматически после завершения работы конструктора.


Т.е при завершении работы конструктора меняется тип объекта?

S>>>>>Ну и я был бы признателен, если бы вы объяснили несведующему, как так получается, что объект константный, но во время работы его конструктора у нас this указывает отнюдь не на константный объект


σ>>>>this во время конструкции константного объекта указаывает, внезапно, на константный объект.


S>>>А тот факт, что якобы константный объект можно менять, вам жить не мешает?


σ>>Нет. Возможно, у тебя при словах "константный объект" возникают какие-то необоснованные ассоциации/представления, то кто тебе виноват?


S>У меня простая ассоциация: константный объект менять нельзя. Это совпадает с тем, что я вижу в языке.

S>Соответственно, если объект можно менять, значит он неконстантный.

Ладно. Я думал это понятно, но, видимо, придётся проговорить явно. Когда я спрашиваю про поведение программы на цепепе, меня интересуют определения стандарта, а не твои. Твои не интересуют.

S>>>Ну так там же и написано, что const на время работы конструктора на объект не распространяется.


σ>>Написано, что const semantics не распространяется.


S>И чтобы это могло значить? Ну, кроме того, что объект не константен.


То, что константен, но модифицировать его (и даже его подобъекты) не UB.
  Скрытый текст
Вообще, идея, что это ещё и на агрегатную инициализацию распространяется, а не только на инициализацию конструктором, но этот дефект на тему обсуждения константности+NRVO не влияет


S>>>Т.е. пока инициализация не завершилась нет никакого константного объекта.


σ>> а что инициализируем тогда?


S>Объект. Который затем станет константой.


Может покажешь в стандарте про смену типа объекта при возврате из конструктора?

σ>>Если применяется NRVO, и тогда переменные s и t обозначают один и тот же объект, то по-твоему

σ>>1. Инициализация для этого объекта заканчивается в S s;?
σ>>2. Или заканчивается только после возвращения из функции, и значит внутри он — неинициализированный (и, следовательно, его lifetime ещё не начался, и, следовательно, обращаться к его членам — UB)?

S>По моему, здесь следует видеть два объекта:


S>* s внутри f() неконстантный;

S>* t вне f() константный.

S>Поскольку одновременно они не сущуствуют и использоваться одновременно не могут


Если ты про область видимости переменных s и t,
struct S { int i; };

S f();

const S t = f();

S f()
{
  S s;

  s.i = 0;

  return s;
}

то вот, внутри функции s и t доступны "одновременно".

S> то тот факт, что они являются одним объектом с точки зрения одной конкретной оптимизации -- это просто мелкая деталь реализации, не более того.


Оно, конечно, деталь реализации в том смысле, что какие-то реализации могут делать, а какие-то нет, но вообще это происходит на уровне абстрактной машины C++ (примерно как то, что размер int это "деталь реализации"). И (не)применение NRVO отличимо в смысле наблюдаемого поведения этой машины (так же, как размер int).

В отличие от чего-нибуть типа будет ли под int i = 0; выделяться место, или будет только в регистре, или вообще i не использовалось и было выкинуто.
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:14
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>Если по семантике C++ это один и тот же объект

V>>Нет никаких "если".
V>>Не считает.
σ>Очередной беспруфный вскукарек засчитан

На это уже отвечалось — пруфом является сам код.
Re[102]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:17
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>this во время конструкции константного объекта указаывает, внезапно, на константный объект.

V>>this указывает на неконстантный объект, в чём ты можешь легко убедиться.
σ>this указывает на константный объект, в чём ты можешь легко убедиться.

Константность проверяется от противного — я могу вызвать внешнюю ф-ию через неконстантный this безо-всяких кастов.


V>>И в чём твоя проблема?

V>>Гугл-переводчик сломался?
V>>RV-оптимизация происходит, на секундочку, над конструктором копирования.
V>>Или это тебе не конструктор уже? ))
σ>Ты, походу, уже совсем почти бессвязную белеберду выдаёшь.

В отсутствии понимания любая примитивщина кажется белибердой. ))
Ликбез: RVO — это про избегание операции копирования.
Re[98]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:26
Оценка:
Здравствуйте, vopl, Вы писали:

V>вот тут внимательно посмотри

V>в исходном примере имеем const std::map<int, int> someDictionary = buildMap();
V>в развертке же ссылка

Которой по-факту не существует — под неё не выделяется память.
Прямо по стандарту компилятору позволяется рассматривать такую ссылку как алиас другой переменной, если ссылка инициализируется именно так — в области видимости ссылаемой переменной/значения.


V>без эмоций подумай эту разницу.


В этой разнице надо ориентироваться.
Просто коллега не был в курсе, что ты этого не знаешь, подразумевал как само собой разумеющееся.


V>Конкретнее — в исходном случае получаем NRVO, а следовательно получаем и ситуацию с двумя декларациями одного и того же объекта, одну внутри функции вторую снаружи.


С тремя значениями объекта, если быть точнее.
В исходном примере нивелируются 2 конструктора копирования:
1. при возврате значения из ф-ии во временный объект;
2. при конструировании переменной от временного объекта.


V>И одна из них делает объект константным.


При возврате значения во временный объект тип объекта не меняется, кстате.
(хотя это и не принципиально)


V>Один и тот же объект. Внимательно присмотрись, без предубеждений


Смотреть надо только на код.
В коде прямо прописано, что вызывается конструктор копирования от временного значения, возвращаемого ф-ей buildMap().
Попробуй запретить конструктор копирования, чтобы убедиться:
http://www.rsdn.org/forum/cpp/8585111.1

В дебажной версии так и будет 2 конструктора копирования.
Re[104]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 20:32
Оценка: +1 -2 :))
Здравствуйте, σ, Вы писали:


σ>Если ты про область видимости переменных s и t,

σ>
struct S { int i; };

σ>S f();

σ>const S t = f();

σ>S f()
σ>{
σ>  S s;

σ>  s.i = 0;

σ>  return s;
σ>}

σ>то вот, внутри функции s и t доступны "одновременно".

Наконец-то интересный пример.
Добиваем мусорными полями, чтоб объект не мог вернуться в регистрах, и...

#include <stdio.h>
#include <stdlib.h>

struct S { int i; double d; int j; };

S f();

const S t = f();

S f()
{
  S s;
  printf("t.i=%i\n", t.i);
  s.i = 42;
  printf("t.i=%i\n", t.i);

  return s;
}

int main() {
    return 0;
}

Вывод:
t.i=0
t.i=42

Правда константность тут нипричом. Если убрать её, будет то же самое. Короче я всё ещё жду UB
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[98]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:33
Оценка:
Здравствуйте, σ, Вы писали:

σ>>>1. При NRVO, переменная result внутри функции и someDictionary вне — обозначают один и тот же объект?

V>>Не одновременно, и этого достаточно.
σ>Чё ты цепляешься за это "не одновременно" как за соломинку?

Не-не-не, это ты пытаешься съехать, мол, "это не я накосячил, это так прописано в стандарте".
В стандарте для UB надо пытаться изменять константный объект, а для этого надо каким-либо образом реинтерпретировать объект или его память как неконстантную.


σ>"Не одновременно" это ты про то, что инициализируемая константная переменная вне области видимости тела функции? Тоже мне, проблема:

σ>
struct S { int i; };

σ>S f();

σ>const S t = f();

σ>S f()
σ>{
σ>  S s;

σ>  s.i = 0;

σ>  return s;
σ>}


"Проблема" никуда не делась — после выхода из f переменной s более не существует, а переменная t только появляется через вызов конструктора копирования.


V>>Ты бы оперировал полностью подробностями:

σ>Ты подробностями называешь детали реализации?

Детали RVO


σ>Нахер ими вообще оперировать, рассуждая о семантике C++, можешь объяснить сперва?


О чём тебе и говорилось изначально — ты можешь рассматривать свой код как будто в нём нет никакого RVO. ))


σ>Семантика C++ не зависит от того, подготавливается там область памяти, или область хуямяти, или программа с бумажкой и карандашом интерпретируется.


Верно, но с одной оговоркой про побочные эффекты в конструкторах/деструкторах.
И об этих пообочных эффектах в стандарте говорится прямо — дабы ты не прозевал подробности. ))

А так-то да, можно договориться до чего угодно, если лезть "унутре", ведь при вызове банальных переопределённых виртуальных ф-ий даже происходит даункаст ссылочного типа this, и ничего! Все живы! Потому что эта механика спрятана, гарантируется корректное преобразование типа (вплоть до смещения адреса при множественном наследовании) и прочие тонкости, которые не должны тебя волновать.

Так же и в случае RVO — корректность кода пострадать не должна, если не будет побочных эфффектов.
Остальные твои попытки заглянуть под капот — спекуляции чистой воды. ))
Но даже и с учётом этой попытки тебя уже тыкали в то, что ты не можешь оперировать ссылкой/переменной на константный объект, бо этой ссылки еще не существует.
Отредактировано 21.08.2023 21:30 vdimas . Предыдущая версия . Еще …
Отредактировано 21.08.2023 21:30 vdimas . Предыдущая версия .
Re[98]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:41
Оценка:
Здравствуйте, vopl, Вы писали:

V>>>при этом сам объект (созданный в __buildMap над __buildMap_result) — уже не константный

V>>Не "уже не константный", а "еще не константный"
V>Имено "уже не константный". В исходном примере он был константный, а потом ув. so5team его развернул и объект стал не костантным.

Дудки, so5team показал императивные шаги происходящего достаточно близко к происходящему (за исключением явного выделения места в стеке — ф-ия обычно заранее знает размер своего локального фрейма стека и заранее раскидывает по нему адреса переменных).

В исходном примере константного объекта еще не было, было лишь место под него.
Похоже, тебя смущает запись присваивания справа налево. ))

Кстате, были как-то предложения добавить оператор записи/присваивания в конце выражения, а не в начале, но сдулось.

В общем, в исходном примере сначала вычисляется выражение справа, а только потом происходит конструирование объекта слева.
До окончания конструирования объекта у тебя нет возможности оперировать его переменной — что и показала развёртка от so5team.

Кстате, в исходном примере можно было переделать на ссылку, чтобы ты по мелочам не придирался:
const std::map<int, int> & map = buildMap();

И ничего не изменится, после всех оптимизаций (просто в этом случае будет одна оптимизация копирования, а не две, как в исходном примере).
Re[94]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:49
Оценка:
Здравствуйте, σ, Вы писали:

V>>Ты на вопрос не ответил.

σ>Конструируя объект типа const T, конструируем константный объект, т.к. по определению объект типа const T это константный объект (const object).

Ты повторяешь это уже 20-й раз, и 20-й раз тебя спрашивают: "Ну, и???"
Ведь не бывает конструктора объекта const T, есть конструктор просто T.

И вообще, это придурь уже какая-то, бо тебе уже подсказывали (с самого начала твоей упёртости), что конструирование — это императивный пошаговый процесс, в общем случае требующий последовательного изменения полей (то бишь состояния) объекта.

До окончания конструирования объект считается неинициализированным, т.е. его нельзя рассматривать как объект — это просто куча байт в памяти.
Соотв., все рассуждения про эту кучу байт как про объект — ошибочны.

А придурь она будет в любом случае, бо эти вещи ты и сам должен понимать.
А если не понимаешь — то молча внимаешь и очень вежливо спрашиваешь, изо всех сил пытаясь понять, что тебе говорят, бгг...


σ>Вот определение: https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const.

σ>Могу даже скопировать определение сюда
>> A const object is an object of type const T
σ>Охренеть как сложно, да?

Летели два крокодила, один зеленый, другой на север.
Тоже ничего сложного, но очень глупо. ))


σ>>>Его ты, видимо, тоже не смог понять

V>>Так нечего понимать — ты не даёшь строгих определений
σ>Вот определение, даю в третий, если не больше, раз: https://timsong-cpp.github.io/cppwp/n4868/basic.type.qualifier#def:object,const. Строже него нет.

Ты должен был дать строгое определение возникающему UB, но ты его так и не дал.
И никогда дать не сможешь, ес-но, бо стоит тебе только попытаться и ты увидишь, как облажался. ))

Причём, тебе в первом же ответе подсказали, где именно ты облажался — ты пытался рассуждать так, будто константная и неконстантная отсылка к объекту валидны одновременно, дважды бгг...
Re[105]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 20:50
Оценка:
TB>Правда константность тут нипричом. Если убрать её, будет то же самое.
Л — логика
Re[106]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 20:51
Оценка:
Здравствуйте, σ, Вы писали:

TB>>Правда константность тут нипричом. Если убрать её, будет то же самое.

σ>Л — логика

Так а где обещанное тобой UB?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[102]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 20:54
Оценка: -1 :)
Здравствуйте, σ, Вы писали:

S>>Еще раз: переменной вне нет пока порождающая функция не завершилась. Место под переменную есть, переменной нет.

σ>Какое ещё место под переменную? Ты случайно не путаешь переменные и объекты?

В данном случае (при хранении по значению) это одно и то же.
Re[107]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 20:59
Оценка:
TB>Так а где обещанное тобой UB?
Так а где описание ожидаемой логики?
Re[108]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 21:00
Оценка: -1 :))
Здравствуйте, σ, Вы писали:

σ>Так а где описание ожидаемой логики?


Плейграунд любой открой и запусти. Одно и то же в дебаге, релизе, с константой, без. Где UB?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 21:02
Оценка:
Здравствуйте, σ, Вы писали:

S>>Автоматически после завершения работы конструктора.

σ>Т.е при завершении работы конструктора меняется тип объекта?

Добавляется модификатор типа, считай что объект "запечатывается".
И это абсолютно законно, бо до завершения конструктора ты не можешь извне пользоваться этим объектом.

По-факту, не существует разницы м/у константным и неконстантым объектом с т.ч. занимаемой им памяти и даже прикладных инвариантов.

Разница есть в системе допущений, которыми вправе пользоваться компилятор в процессе оптимизации, например, не запрашивать некие поля или не вычислять некие значения от полей объекта повторно. Т.е. потенциальное UB возможно из-за неверных этих допущений, если горе-программист хакнул собственный константный объект, радостно обманув глупый компилятор.
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 21:04
Оценка:
Здравствуйте, σ, Вы писали:

σ>то вот, внутри функции s и t доступны "одновременно".


Переменная t внутри f еще не существует, а значит недоступна.
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 21:07
Оценка:
Здравствуйте, σ, Вы писали:

σ>Вроде всё началось с того, что я задал вопрос про константность объекта.


На что сразу же получил ответ, что объекта, который ты имел ввиду, еще не существует в рассматриваемой точке инициализации.
Re[109]: Когда это наконец станет defined behavior?
От: σ  
Дата: 21.08.23 21:09
Оценка:
σ>>Так а где описание ожидаемой логики?

TB>Плейграунд любой открой и запусти. Одно и то же в дебаге, релизе, с константой, без.


Теперь тебе осталось всего ничего: предоставить пруф, что такое и должно быть согласно спеке.
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 21:09
Оценка:
Здравствуйте, vopl, Вы писали:

V>Во первых, не вижу необходимости кому либо что то демонстрироать. Обрати внимание, я называю сабжевое UB "гипотетическим", "подозреваемым".


И какое неопределённое поведение тут может быть?
Пусть даже самое гипотетическое?
Re[110]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 21.08.23 21:14
Оценка:
Здравствуйте, σ, Вы писали:

σ>Теперь тебе осталось всего ничего: предоставить пруф, что такое и должно быть согласно спеке.


Вот пруф для балаболов-любителей тупой демагогии: http://godzilla.vfose.ru/
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 21.08.23 21:19
Оценка:
Здравствуйте, vopl, Вы писали:

V>Вероятно, это недоработка языка.


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


V>Примерно такая же, что и привела к сабжевому гипотетическому UB — стандарт определил:

V>1. что тип объекта определяется его декларацией
V>2. модифицировать константный объект — UB
V>3. и тут добавили положение про NRVO, которое сделало возможным один и тот же объект задекларировать два раза, причем по разному (с константностью и без). И вот этот третий пункт с учетом предыдущих двух формирует всю обсуждаемую в текущей подветке котовасию

Это так не работает, реально. ))

Абсолютно любое потенциальное UB из стандарта может быть достаточно легко объяснено "на пальцах" — откуда может взяться расхождение описанного в коде и реально происходящего.

Конкретно в этой ситуации лично я не вижу потенциального UB, которое можно было бы размуно объяснить.
(оговорку про использование неинициализированных глобальных переменных сделал сразу же, но эта оговорка справедлива к любым таким переменным, необязательно константным)

В итоге, ни ты, ни твой союзник не показали сути этого потенциального UB, кроме как через малосвязанные пункты из стандарта, где эту связь вы насосали из пальца.
Суть вашего насоса вам сразу же сообщили и даже показали в "развёртке" — ссылание на объект неодновременно, а подразумеваемый вами UB должен случиться при одновременном наличии константной и неконстантной отсылки к объекту.

В этом месте вы упёрлись и давай нас развлекать. ))


V>Это дело вкуса. Для меня, например, стандарт — это правила игры в язык C++.


стандарт описан не для домохозяек, а для специалистов с неким ненулевым бэкграундом



V>Если кто то хочет играть в игру на основе собственного понимания правил — пожалуйста, но стандарт — это источник первичного смысла в ней.


Только надо делать скидку на то, что стандарт С++ использует достаточно вольную трактовку понятия "объект", где на самом деле это не объект из ООП и даже не объект в терминологии С++ (где объект — это экземпляр класса, структуры или объединения), а просто любой экземпляр любого типа.
Re[98]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 21.08.23 22:14
Оценка: +1
Здравствуйте, σ, Вы писали:

  Скрытый текст
std::map<int, int> buildMap() {
    std::map<int, int> result;

    result.insert(42, 43); 
    ...
    return result;
}

const std::map<int, int> someDictionary = buildMap();

σ>И что «lifetime»? Он начинается внутри функции, после инициализации result.
Когда начинается lifetime объекта someDictionary ? Тогда, когда заканчивается конструирование объекта.
В выражении const std::map<int, int> someDictionary = buildMap(); вызов buildMap() sequenced before инициализации someDictionary, а значит значение для инициализации должно быть получено до начала lifetime объекта someDictionary. А до этих пор константный объект можно модифицировать.

И каждый день — без права на ошибку...
Re[99]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 00:03
Оценка: :)
σ>>И что «lifetime»? Он начинается внутри функции, после инициализации result.
BFE>Когда начинается lifetime объекта someDictionary ? Тогда, когда заканчивается конструирование объекта.

Ну. При NRVO, оно заканчивается на std::map<int, int> result;.

BFE>В выражении const std::map<int, int> someDictionary = buildMap(); вызов buildMap() sequenced before инициализации someDictionary, а значит значение для инициализации должно быть получено до начала lifetime объекта someDictionary. А до этих пор константный объект можно модифицировать.


Получается, result.insert(42, 43); — UB, т.к. после старта лайфтайма?

Или объект сначала вроде как создаётся константным (const std::map<int, int> someDictionary), но потом становится неконстантным (std::map<int, int> result;), а опять константным не становится, и его можно менять даже после const std::map<int, int> someDictionary = buildMap();?
Отредактировано 22.08.2023 0:09 σ . Предыдущая версия .
Re[100]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 04:54
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>>>похоже, мы разговариваем на разных языках.. Причем тут оптимизатор — категорически не понимаю.


S>>Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.


V>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


Так там про NRVO прямым текстом:

что если происходит NRVO


V>Выше приводил конкретные 5 пунктов, даже с косвенной отсылкой на стандарт, посредством которых мною допускается гипотеза сабжевого UB.


Простите, я скипну, поскольку эти 5 пунктов напоминают фокусы из категории "как математически доказать, что 2+2 равно 5". Вот так и здесь люди надергают цитат из стандарта не потрудившись согласовать их друг с другом, а потом выводят вещи, которые не имеют смысла. Простите, если это звучит резко.

V>Не припомню чтобы в твою сторону что то осталось без ответа.


Зато я помню (точнее, могу найти т.к. здесь все ходы записаны): http://rsdn.org/forum/cpp/8583454.1
Автор: so5team
Дата: 18.08.23
(и чуть выше по ветке). Тов.σ не смог продолжить разговор про отсутствие константности в конструкторе, а там это был, имхо, ключевой момент.

V>Это дело вкуса. Для меня, например, стандарт — это правила игры в язык C++. Если кто то хочет играть в игру на основе собственного понимания правил — пожалуйста, но стандарт — это источник первичного смысла в ней. Аналогично можно было бы сказать, что законы написаны для юристов, а потом недоумевать, почему мне штрафы сыпятся и почему меня в тюрьму сажают.


Нет. Законы должны быть донесены до потребителя в простой и, желательно, логичной форме. Тогда как юридические формулировки законов -- это особый стиль записи предназначенный для того, чтобы максимально исключить неоднозначность трактовки. Аналогично и в стандарте: стандарт должен быть таким, чтобы независимые разработчики компилятора смогли реализовать по стандарту одно и тоже.

У программистов, использующих C++, задача иная. По хорошему им в стандарт вообще не должно быть нужно заглядывать, разве что лишь в каких-то неоднозначных моментах.
Re[82]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 05:01
Оценка: 1 (1) +1
Здравствуйте, σ, Вы писали:

V>>
σ>std::map<int, int> buildMap() {
σ>    std::map<int, int> result;

σ>    result.insert(42, 43); // мутабельность
σ>}

σ>const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект
σ>

σ>Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект. Он будет константным?

Какой-то здесь, право слово, фигней страдают, пытаясь найти некий гипотетический UB. Хотя с NRVO и получением константного объекта из неконстантного можно запросто наступить на несложные грабли:

  Пример кода
#include <iostream>
#include <set>

class entity;
class entity_registry;

class entity {
    entity_registry * registry_{};
    int value_{};

public:
    entity() = default;
    entity(entity_registry * registry);
    ~entity();

    int value() const noexcept;

    void update(int delta);
};

class entity_registry {
    std::set<entity *> entities_;

public:
    void add(entity & ent) {
        entities_.insert(&ent);
        std::cout << "add to registry: " << &ent << std::endl;
    }
    void remove(entity & ent) {
        entities_.erase(&ent);
        std::cout << "removed from registry: " << &ent << std::endl;
    }

    void update(int delta) {
        for(auto * ent : entities_) ent->update(delta);
    }
};

entity::entity(entity_registry * registry) : registry_{registry} {
    registry_->add(*this);
}

entity::~entity() {
    if(registry_) registry_->remove(*this);
}

int entity::value() const noexcept {
    return value_;
}

void entity::update(int delta) {
    value_ += delta;
}

void consume_one(const entity & ent) {
    std::cout << "consume_one: " << ent.value() << std::endl;
}

void consume_two(const entity & ent) {
    std::cout << "consume_two: " << ent.value() << std::endl;
}

entity make_entity(entity_registry & registry) {
    entity ent{&registry};
    ent.update(42);
    return ent;
}

void demo() {
    entity_registry registry;
    const entity ent = make_entity(registry);

    std::cout << "value: " << ent.value() << std::endl;
    consume_one(ent);
    registry.update(100);
    consume_two(ent);
}

int main() {
    demo();
}


Суть в том, что неконстантный объект сохраняет себя в реестре. Но, т.к. деструктор для него не вызывается, то из реестра этот объект не удаляется. Но указатель на объект остается валидным, т.к. объект преобразуется в константу в вызывающей функции. Однако, т.к. реестр хранит неконстантный указатель на константный объект, то через реестр мы получаем возможность поменять этот самый константный объект. Что, кмк, есть UB.

GCC-11 (g++ -std=c++17 -O2) на Ubuntu-22.04 выдает вполне ожидаемое:
add to registry: 0x7ffd9a0035b0
value: 42
consume_one: 42
consume_two: 142
removed from registry: 0x7ffd9a0035b0

Даже не пришлось на разные исходные файлы разбивать.
Re[104]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 05:11
Оценка:
Здравствуйте, σ, Вы писали:

S>>>>Не поменяет, а приобретет.


σ>>>Ладно, спрошу как тебе угодно: каким образом приобретёт.


S>>Автоматически после завершения работы конструктора.


σ>Т.е при завершении работы конструктора меняется тип объекта?


При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.
Т.е. если у нас есть:
class demo {
public:
  demo() { ... /* туева хуча кода */ }
  ...
};
...
void f() {
  const demo d; // (1)
}

то в точке (1) сперва запускается конструктор для нового объекта. Внутри конструктора уже есть объект типа demo. Но это пока что не объект d внутри f, т.к. конструктор еще не завершил свою работу. А когда завершает, то в f появляется объект типа "const demo". Просто пока работал конструктор это был некий безымянный объект типа demo, а когда конструктор завершился он же стал именованным объектом d типа "const demo".

σ>Ладно. Я думал это понятно, но, видимо, придётся проговорить явно. Когда я спрашиваю про поведение программы на цепепе, меня интересуют определения стандарта, а не твои. Твои не интересуют.


Тут остается разве что поинтересоваться а чем ваше стремление увидеть цитату из стандарта отличается от "начетничества".

S>>>>Ну так там же и написано, что const на время работы конструктора на объект не распространяется.


σ>>>Написано, что const semantics не распространяется.


S>>И чтобы это могло значить? Ну, кроме того, что объект не константен.


σ>То, что константен, но модифицировать его (и даже его подобъекты) не UB.


Если что-то можно модифицировать (и это не mutable поле), то это не константа. Смысл константности в том, что изменять это нельзя.

Но если для вас смысл константности в том, что в стандарте написано, что константой считается то, что объявлено как const, то здесь остается только развести руками.

σ>Может покажешь в стандарте про смену типа объекта при возврате из конструктора?


Нет.

σ>Если ты про область видимости переменных s и t,


Нет, не про область видимости.

σ>
struct S { int i; };

σ>S f();

σ>const S t = f();

σ>S f()
σ>{
σ>  S s;

σ>  s.i = 0;

σ>  return s;
σ>}

σ>то вот, внутри функции s и t доступны "одновременно".

Нет.

Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.
Re[83]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 22.08.23 06:18
Оценка:
Здравствуйте, so5team, Вы писали:

S>entity make_entity(entity_registry & registry) {

S> entity ent{&registry};

S>Суть в том, что неконстантный объект сохраняет себя в реестре.


А всё потому, что нефиг ссылки на локалки сохранять во внешнем объекте.
Правда если бы не сработало РВО, то тупо локальный объект бы сам себя удалил из реестра.

Короче код на грани фола, и слово const тут его уже не спасает
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 22.08.2023 6:21 T4r4sB . Предыдущая версия .
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 06:57
Оценка: -1
Здравствуйте, vdimas, Вы писали:

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


V>>Во первых, не вижу необходимости кому либо что то демонстрироать. Обрати внимание, я называю сабжевое UB "гипотетическим", "подозреваемым".


V>И какое неопределённое поведение тут может быть?

V>Пусть даже самое гипотетическое?

тут
Автор: vopl
Дата: 21.08.23
, после слов "почему тут подозревается UB:" 5 пунктов разъясняющих гипотетическое UB
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 07:02
Оценка: -1
Здравствуйте, vdimas, Вы писали:

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


V>>Вероятно, это недоработка языка.


V>Или собственное непонимание, ведь стандарт описан не для домохозяек, а для специалистов с неким ненулевым бэкграундом.


у вас тут секта грубиянов чтоли?
Re[84]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 07:10
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Правда если бы не сработало РВО, то тупо локальный объект бы сам себя удалил из реестра.


ВотЪ!

TB>Короче код на грани фола


На грани фола здесь то, что нет явно определенных пользователем конструкторов копирования/перемещения. Которые либо автоматически бы добавляли новый объект в реестр, либо же запрещали его изъятие из реестра в деструкторе. Впрочем, здесь это преднамеренно не проблема, т.к. попытка удаления из реестра объекта, который в реестре не зарегистрирован, заведомо безопасна.

Так что в целом с дизайном entity и entity_registry все более-менее ОК для маленького демонстрационного примера.

TB>и слово const тут его уже не спасает


А оно и не может.
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 07:11
Оценка: :)
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>>>похоже, мы разговариваем на разных языках.. Причем тут оптимизатор — категорически не понимаю.


S>>>Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.


V>>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


S>Так там про NRVO прямым текстом:

что если происходит NRVO


однозначно свзяываешь NRVO и оптимизацию? Это не так, NRVO может иметь место и без оптимизации, оптимизация может не применить NRVO.

V>>Выше приводил конкретные 5 пунктов, даже с косвенной отсылкой на стандарт, посредством которых мною допускается гипотеза сабжевого UB.


S>Простите, я скипну, поскольку эти 5 пунктов напоминают фокусы из категории "как математически доказать, что 2+2 равно 5". Вот так и здесь люди надергают цитат из стандарта не потрудившись согласовать их друг с другом, а потом выводят вещи, которые не имеют смысла. Простите, если это звучит резко.


К сожалению, это все голословно. Вот если бы ты показал в этих пунктах ошибку, которая покажет несостоятельность сделанного вывода..

V>>Не припомню чтобы в твою сторону что то осталось без ответа.


S>Зато я помню (точнее, могу найти т.к. здесь все ходы записаны): http://rsdn.org/forum/cpp/8583454.1
Автор: so5team
Дата: 18.08.23
(и чуть выше по ветке). Тов.σ не смог продолжить разговор про отсутствие константности в конструкторе, а там это был, имхо, ключевой момент.


Ухты пухты. Я не отвечаю за тов. σ, я отвечаю только за себя.

V>>Это дело вкуса. Для меня, например, стандарт — это правила игры в язык C++. Если кто то хочет играть в игру на основе собственного понимания правил — пожалуйста, но стандарт — это источник первичного смысла в ней. Аналогично можно было бы сказать, что законы написаны для юристов, а потом недоумевать, почему мне штрафы сыпятся и почему меня в тюрьму сажают.


S>Нет. Законы должны быть донесены до потребителя в простой и, желательно, логичной форме. Тогда как юридические формулировки законов -- это особый стиль записи предназначенный для того, чтобы максимально исключить неоднозначность трактовки. Аналогично и в стандарте: стандарт должен быть таким, чтобы независимые разработчики компилятора смогли реализовать по стандарту одно и тоже.


S>У программистов, использующих C++, задача иная. По хорошему им в стандарт вообще не должно быть нужно заглядывать, разве что лишь в каких-то неоднозначных моментах.


Услышал твое мнение/позицию, ок.
Re[85]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 22.08.23 07:18
Оценка:
Здравствуйте, so5team

S>На грани фола здесь то, что нет явно определенных пользователем конструкторов копирования/перемещения.


Использование мув конструктора чтоб фиксить ссылки в реестре — ну это допустимо по правилам цпп, но по мне так это полная дичь, и тащить это в язык я б не стал. Необходимость думать про такие случаи тяжелым крестом лежит на плечах крестокомпилятора, изза чего он даже не может передать юник в регистрах, или реаллоцировать вектор простым realloc.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[102]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 22.08.23 07:20
Оценка:
Здравствуйте, vopl, Вы писали:

V>у вас тут секта грубиянов чтоли?


У вас тут секта демагогов что ли?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[99]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 07:22
Оценка: :)
Здравствуйте, vdimas, Вы писали:

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


V>>вот тут внимательно посмотри

V>>в исходном примере имеем const std::map<int, int> someDictionary = buildMap();
V>>в развертке же ссылка

V>Которой по-факту не существует — под неё не выделяется память.

V>Прямо по стандарту компилятору позволяется рассматривать такую ссылку как алиас другой переменной, если ссылка инициализируется именно так — в области видимости ссылаемой переменной/значения.

Не на то смотришь.
V>>в исходном примере имеем const std::map<int, int> someDictionary = buildMap();
то есть, имеет место декларация имени someDictionary и объекта типа const std::map<int, int>

V>>в развертке же ссылка

снова декларация имени someDictionary (это не важно) НО теперь совершенно другого объекта (он имеет уже ссылочноый тип и связывается с тем первичным объектом, но это тоже не важно)
то есть, тот первичный объект никак не определяется в этом месте. Соответственно, не получает тип const std::map<int, int>
вот в этом и есть разница. В исходном примере он получил тип const std::map<int, int> а в "развертке" от so5team — не получил.

моя дальнейшая логика будет строиться на этом различии. В чем я тут ошибаюсь?
Re[102]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 07:25
Оценка:
Здравствуйте, vopl, Вы писали:

V>>И какое неопределённое поведение тут может быть?

V>>Пусть даже самое гипотетическое?
V>тут
Автор: vopl
Дата: 21.08.23
, после слов "почему тут подозревается UB:" 5 пунктов разъясняющих гипотетическое UB


Тебе на это уже отвечали:

Это так не работает, реально. ))

Абсолютно любое потенциальное UB из стандарта может быть достаточно легко объяснено "на пальцах" — откуда может взяться расхождение описанного в коде и реально происходящего.

Конкретно в этой ситуации лично я не вижу потенциального UB, которое можно было бы разумно объяснить.
(оговорку про использование неинициализированных глобальных переменных сделал сразу же, но эта оговорка справедлива к любым таким переменным, необязательно константным)

В итоге, ни ты, ни твой союзник не показали сути этого потенциального UB, кроме как через малосвязанные пункты из стандарта, где эту связь вы насосали из пальца.
Суть вашего насоса вам сразу же сообщили и даже показали в "развёртке" — ссылание на объект неодновременно, а подразумеваемый вами UB должен случиться при одновременном наличии константной и неконстантной отсылки к объекту.



V>5. следовательно, модификация s.i = 0 подозревается в UB


Никаких "следовательно", бо константного объекта еще не существует, отсылка к нему невалидна, т.к. сам объект еще не создан.

В любом случае, это не ответ на заданный вопрос — в чём именно заключается UB???

Для ответа на этот вопрос следует не ссылаться на стандарт, а ровно наоборот — брать упоминание UB из стандарта и пояснить своё понимание — каким образом в той или иной ситуации возникает неопределённое поведение в терминах происходящего в вычислительной модели С++ в рантайме.

Вот пример объяснения UB, возникающего из хака константности, на который вы ссылаетесь:

Разница есть в системе допущений, которыми вправе пользоваться компилятор в процессе оптимизации, например, не запрашивать некие поля или не вычислять некие значения от полей объекта повторно. Т.е. потенциальное UB возможно из-за неверных этих допущений, если горе-программист хакнул собственный константный объект, радостно обманув глупый компилятор.


Итого, просьба породить пример, который избегает UB по глобальной инициализации, но потенциально содержит UB по "хаку" константности, при этом необходимо указать не пункт стандарта, а объяснить суть потенциального UB (даже если оно не наблюдается в мейнстримовых актуальных компиляторах).

Не сможете пояснить суть UB — слили.
Отредактировано 22.08.2023 7:57 vdimas . Предыдущая версия . Еще …
Отредактировано 22.08.2023 7:56 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 7:56 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 7:55 vdimas . Предыдущая версия .
Re[99]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 07:26
Оценка: :)
Здравствуйте, vdimas, Вы писали:

V>Кстате, в исходном примере можно было переделать на ссылку, чтобы ты по мелочам не придирался:

V>
V>const std::map<int, int> & map = buildMap();
V>

V>И ничего не изменится, после всех оптимизаций (просто в этом случае будет одна оптимизация копирования, а не две, как в исходном примере).

В этом случае изменится весь кейс. Пропадет NRVO, пропадет вторая декларация "того же самого объекта", пропадает его константность, пропадает "модификация константного объекта", пропадает то "гипотетическое UB".
Re[102]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 07:29
Оценка: +2
Здравствуйте, vopl, Вы писали:

S>>>>Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.


V>>>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


S>>Так там про NRVO прямым текстом:

что если происходит NRVO


V>однозначно свзяываешь NRVO и оптимизацию?


Так там прямо из названия следует: Named Return Value Optimization.
Если что-то называется "оптимизацией", да и ведет себя как "оптимизация", то это оптимизация и есть.

V>Это не так, NRVO может иметь место и без оптимизации, оптимизация может не применить NRVO.


Правильно ли я понимаю, что для вас оптимизация -- это когда флаги компилятору вроде -O1 или -O2 передаются?
Так-то компилятор может проводить оптимизации (т.е. устранять избыточный код) и без этих самых флагов, AFAIK.

S>>Простите, я скипну, поскольку эти 5 пунктов напоминают фокусы из категории "как математически доказать, что 2+2 равно 5". Вот так и здесь люди надергают цитат из стандарта не потрудившись согласовать их друг с другом, а потом выводят вещи, которые не имеют смысла. Простите, если это звучит резко.


V>К сожалению, это все голословно. Вот если бы ты показал в этих пунктах ошибку, которая покажет несостоятельность сделанного вывода..


Так тут уже много-много раз пытались. Вы хотите еще один подход?

Чтож, давайте попробуем. Подозрение в наличии UB у некоторых возникает из-за того, что они думают, что константный объект сперва появляется в вызывающей функции, затем модифицируется в вызываемой. И, т.к. в вызывающей функции он константен, то в вызываемой происходит модификация константного объекта.

Однако, людям, которые страдают этим подозрением следовало бы доказать и себе, и всем окружающим, что константный объект сперва появляется в вызывающей функции. И что лишь потом к нему обращается вызываемая. А это, мягко говоря, неочевидно.

Следовательно, пока не доказано что константный объект начал жить раньше, чем была вызвана функция, мы имеем неконстантный объект внутри вызванной функции. А раз он неконстантный, то его модификация не UB. Потом, в силу NRVO, этот объект не умирает, а остается жить внутри вызывающей функции, но уже как константный. Т.е. константный объект физически появляется в вызывающей функции только после завершения работы вызванной.

Поскольку я не знаток стандарта, то подтвердить цитатами все это не смогу. Да и вроде незачем, т.к. УМВР
Re[86]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 07:34
Оценка:
Здравствуйте, T4r4sB, Вы писали:

S>>На грани фола здесь то, что нет явно определенных пользователем конструкторов копирования/перемещения.


TB>Использование мув конструктора чтоб фиксить ссылки в реестре — ну это допустимо по правилам цпп, но по мне так это полная дичь


Конкретно в этом случае смысл move-конструктора/оператора далеко не очевиден. Если внутри entity нет каких-то тяжелых данных, то по-хорошему, для такой ситуации move-конструктор/оператор вообще следовало бы запретить.
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 07:48
Оценка:
Здравствуйте, vopl, Вы писали:

V>>Прямо по стандарту компилятору позволяется рассматривать такую ссылку как алиас другой переменной, если ссылка инициализируется именно так — в области видимости ссылаемой переменной/значения.

V>Не на то смотришь.

Наоборот, заставляю тебя смотреть "на то", бо ниже ты опять косячишь в рассуждениях — продолжаем ликбез! ))


V>>>в исходном примере имеем const std::map<int, int> someDictionary = buildMap();

V>то есть, имеет место декларация имени someDictionary и объекта типа const std::map<int, int>

Не бывает декларации объекта. ))
Тут декларация переменной обычного (не ссылочного) типа, т.е. введение строкового идентификатора для алиаса численного адреса некоего значения.


V>>>в развертке же ссылка

V>снова декларация имени someDictionary (это не важно) НО теперь совершенно другого объекта (он имеет уже ссылочноый тип и связывается с тем первичным объектом, но это тоже не важно)

Э, нет — это архиважно!

Я могу написать так:
const std::map<int, int> & immutableMap = buildMap();

Но не могу так:
std::map<int, int> & immutableMap = buildMap();

Потому что захватить для владения временный объект я могу только по константной ссылке, т.е. после захвата этого значения оно превращается в константное — к типу значения добавляется соотв. модификатор. И теперь без хака-реинтерпретации памяти ты эту константность никак не нарушишь.

В итоге, компилятор породит идентичный код для случая возврата в переменную по значению и для случая захвата временного объекта по ссылке прямо согласно стандарта, где компилятор имеет право не создавать переменную-ссылку, если алиасинг происходит в области видимости захватываемого ссылкой значения.
Т.е. ссылка будет использоваться в точности как идентификатор-алиас локального адреса данных, отсюда и порождаемый код будет идентичным.


V>то есть, тот первичный объект никак не определяется в этом месте.


Локальный еще как определяется, причём строго и непротиворечиво — просто он безымянный/временный, это результат вызова buldMap().
Но для него точно так же прописано время его жизни в данном scope.


V>Соответственно, не получает тип const std::map<int, int>


Получает этот тип при захвате владения временным объектом через константную ссылку.


V>вот в этом и есть разница.


Это у тебя от непонимания организации времени жизни временных объектов.


V>В исходном примере он получил тип const std::map<int, int> а в "развертке" от so5team — не получил.


На это уже отвечал — в исходном примере можно было изменить на const std::map<int, int> &, и ничего бы не изменилось.
Просто кто же знал, что ты плаваешь еще и в этом ? ))


V>моя дальнейшая логика будет строиться на этом различии. В чем я тут ошибаюсь?


Сразу в нескольких вещах:

1. Непонимание, что есть "переменная".

2. Непонимание алиасинга ссылок времени компиляции (необязательность выделения памяти под переменные-ссылки).

3. Непонимание времени жизни временных безымянных значений, где без продления времени жизни временных значений через константную ссылку, время жизни временного значения отдаётся на откуп компилятору — либо в текущей области видимости, либо в рамках текущего выражения, породившего временное безымянное значение.

4. Непонимание записи вида const T obj = T(42);, где компилятор вправе исключить создание временного объекта согласно предыдущего пункта, т.е. исключить вызов конструктора копирования, хотя, согласно семантике, происходит именно это (копирование временного значения), и для успешной компиляции требуется доступность как конструктора T(int) для создания временного значения, так и конструктора T(const T &) для копирования временного значения в инициализируемую переменную, т.е. в этом выражении во время компиляции используются оба конструктора, хотя в бинарнике останется вызов только T(int).
Отредактировано 22.08.2023 10:19 vdimas . Предыдущая версия . Еще …
Отредактировано 22.08.2023 10:15 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 8:01 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 8:01 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 8:01 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 7:49 vdimas . Предыдущая версия .
Re[100]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 07:54
Оценка:
Здравствуйте, vopl, Вы писали:

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


V>>Кстате, в исходном примере можно было переделать на ссылку, чтобы ты по мелочам не придирался:

V>>
V>>const std::map<int, int> & map = buildMap();
V>>

V>>И ничего не изменится, после всех оптимизаций (просто в этом случае будет одна оптимизация копирования, а не две, как в исходном примере).

V>В этом случае изменится весь кейс.


Не-а.


V>Пропадет NRVO


А почему бы тебе, вместо сотрясения воздуха, предварительно не проверить самостоятельно — пропадается ли NRVO или нет? ))


V>пропадет вторая декларация "того же самого объекта"


Остаётся.
Безымянное/временное значение — такое же "честное" значение, как и локальная переменная, это значение можно захватить для владения в текущем scope.


V>пропадает его константность


Константность не может пропасть, согласно правилам С++ константность можно только добавить.
Обратное будет хаком. ))


V>пропадает "модификация константного объекта", пропадает то "гипотетическое UB".


Если бы вы были в состоянии пояснить суть UB (а не просто ссылаться на стандарт), вы бы увидели, что кейзы равнозначны.

Суть в том, что компилятор не по каждому константному объекту делает некие допущения и соотв.оптимизации, а только когда видит его жизненный цикл.
Т.е. подать константную ссылку извне в ф-ию, или получить константную ссылку на локальное временное значение — две большие разницы.

Во втором случае компилятор рассматривает локальное временное значение как имеющее алиасинг, т.е. в точности так же, как он рассматривал бы локальную константную переменную, куда поместили бы это значение.
Отредактировано 22.08.2023 8:57 vdimas . Предыдущая версия .
Re[105]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 07:58
Оценка:
S>При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.

Что значит появляется?

S>Т.е. если у нас есть:

S>
class demo {
public:
  demo() { ... /* туева хуча кода */ }
  ...
};
...
void f() {
  const demo d; // (1)
}

S>то в точке (1) сперва запускается конструктор для нового объекта. Внутри конструктора уже есть объект типа demo. Но это пока что не объект d внутри f, т.к. конструктор еще не завершил свою работу. А когда завершает, то в f появляется объект типа "const demo". Просто пока работал конструктор это был некий безымянный объект типа demo, а когда конструктор завершился он же стал именованным объектом d типа "const demo".

Не понел, в (1) два объекта, что ли?

S>Если что-то можно модифицировать (и это не mutable поле), то это не константа. Смысл константности в том, что изменять это нельзя.


Ок. А смысл const object — в другом. Меня интересует const object.

S>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.


Можно конкретнее? Пример модификации и причина UB.
Re[106]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 08:09
Оценка:
Здравствуйте, σ, Вы писали:

S>>При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.


σ>Что значит появляется?


Значит появляется. Объяснить эту вещь на еще более тривиальном уровне я не смогу, сорри.

S>>Т.е. если у нас есть:

S>>
σ>class demo {
σ>public:
σ>  demo() { ... /* туева хуча кода */ }
σ>  ...
σ>};
σ>...
σ>void f() {
σ>  const demo d; // (1)
σ>}
σ>

S>>то в точке (1) сперва запускается конструктор для нового объекта. Внутри конструктора уже есть объект типа demo. Но это пока что не объект d внутри f, т.к. конструктор еще не завершил свою работу. А когда завершает, то в f появляется объект типа "const demo". Просто пока работал конструктор это был некий безымянный объект типа demo, а когда конструктор завершился он же стал именованным объектом d типа "const demo".

σ>Не понел, в (1) два объекта, что ли?


Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет (и может не появится, если конструктор demo бросит исключение или дернет std::abort), хотя место под d уже есть.

S>>Если что-то можно модифицировать (и это не mutable поле), то это не константа. Смысл константности в том, что изменять это нельзя.


σ>Ок. А смысл const object — в другом. Меня интересует const object.


Вы в очередной раз отсылаете к этому разделу стандарта. Но там не описан смысл константного объекта. Там дано определение того, что с точки зрения языка считается const object.

S>>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.


σ>Можно конкретнее? Пример модификации и причина UB.


Конкретнее я вообще не говорил про модификацию, а про обращение (обращение не обязательно означает модификацию, чтение так же является обращением).
А пример, пожалуйста:
struct S { int i; };

S f();

const S t = f();

S f()
{
  S s;

  s.i = t.i + 42;

  return s;
}

При первом вызове f(), который произойдет при инициализации t, вы получите UB, т.к. t не инициализирован, следовательно, вы обращаетесь к неинициализированному объекту, что есть UB, если меня окончательно не добил склероз.
Re[103]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 08:19
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>>И какое неопределённое поведение тут может быть?

V>>>Пусть даже самое гипотетическое?
V>>тут
Автор: vopl
Дата: 21.08.23
, после слов "почему тут подозревается UB:" 5 пунктов разъясняющих гипотетическое UB


V>Тебе на это уже отвечали:

V>

V>Это так не работает, реально. ))

V>Абсолютно любое потенциальное UB из стандарта может быть достаточно легко объяснено "на пальцах" — откуда может взяться расхождение описанного в коде и реально происходящего.

V>Конкретно в этой ситуации лично я не вижу потенциального UB, которое можно было бы размуно объяснить.
V>(оговорку про использование неинициализированных глобальных переменных сделал сразу же, но эта оговорка справедлива к любым таким переменным, необязательно константным)

V>В итоге, ни ты, ни твой союзник не показали сути этого потенциального UB, кроме как через малосвязанные пункты из стандарта, где эту связь вы насосали из пальца.

ну, мнение услышал

V>Суть вашего насоса вам сразу же сообщили и даже показали в "развёртке" — ссылание на объект неодновременно, а подразумеваемый вами UB должен случиться при одновременном наличии константной и неконстантной отсылки к объекту.


ну так там оно и есть все "одновременно". Константный объект, используемый сквозь неконстантное имя, подвергается модификации. Каким образом объект является константным я показал, ты опровер это доводом "это так не работает" и "лично я не вижу", у меня против таких опровержений — доводов нет, тут сливаюсь



V>>5. следовательно, модификация s.i = 0 подозревается в UB

V>Никаких "следовательно", бо константного объекта еще не существует, отсылка к нему невалидна, т.к. сам объект еще не создан.

в случае NRVO объект внутри и снаружи — это один и тот же объект (σ приводил ссылку на стандарт), следовательно его время жизни уже началось, он уже создан. Тип этого объекта опледеляется декларацией, коих две штуки и в одной из них он объявлен как константный, то есть, имеются основания полагать что компилятор может его посчитать константным.

V>В любом случае, это не ответ на заданный вопрос — в чём именно заключается UB???

UB возможно исходя из факта модификации объекта, который гипотетически может быть трактован компилятором как константный, (σ приводил ссылку на стандарт)

V>Для ответа на этот вопрос следует не ссылаться на стандарт, а ровно наоборот — брать упоминание UB из стандарта и пояснить своё понимание — каким образом в той или иной ситуации возникает неопределённое поведение в терминах происходящего в вычислительной модели С++ в рантайме.


V>Вот пример объяснения UB, на который вы ссылаетесь:

V>

V>Разница есть в системе допущений, которыми вправе пользоваться компилятор в процессе оптимизации, например, не запрашивать некие поля или не вычислять некие значения от полей объекта повторно. Т.е. потенциальное UB возможно из-за неверных этих допущений, если горе-программист хакнул собственный константный объект, радостно обманув глупый компилятор.


V>Итого, просьба породить пример, который избегает UB по глобальной инициализации, но потенциально содержит UB по "хаку" константности, при этом необходимо указать не пункт стандарта, а объяснить суть потенциального UB (даже если оно не наблюдается в мейнстримовых актуальных компиляторах).


V>Не сможете пояснить суть UB — слили.


давай изначально считать что я слил. Мне интересно разобраться в вопросе а не поэмоционировать

суть UB в том что компилятор на основе константности может сделать допущения, являющиеся ошибочными так как объект используется как не константный. И такие ошибочные допущения могут привести к аномалиям, например:
1. предположим, компилятор таки посчитал объект константным в силу той второй декларации где он имеет константный тип
2. для такого константного объекта компилятор может сделать допущение о том что после его конструирования (внутри функции) его состояние не меняется, следовательно можно упразднить все повторные загрузки из памяти этого состояния (они потребуются при вызове методов объекта внутри функции)
3. при отсутствии повторных загрузок — получаем коррупцию представления состояния объекта. Это негативный эффект от сабжевого UB
Re[102]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 08:34
Оценка:
Здравствуйте, vopl, Вы писали:

V>>Или собственное непонимание, ведь стандарт описан не для домохозяек, а для специалистов с неким ненулевым бэкграундом.

V>у вас тут секта грубиянов чтоли?

Дык, вы ж не показали понимание прочитанного в стандарте.

Давай я покажу тебе суть того UB, на который вы ссылаетесь, где этот UB можно получить безо-всяких реинтерпретаций/хаков:
#include <vector>
#include <iostream>

class SomeObj;

class Registrar {
    std::vector<SomeObj*> regs_;
    int index {};

public:
    void registerObj(SomeObj * obj);
    void incrementAll();
};

class SomeObj {
public:
    SomeObj(Registrar & reg) {
        reg.registerObj(this);
    }

    int index {};
};

void Registrar::registerObj(SomeObj * obj) {
    obj->index = index++;
    regs_.push_back(obj);
}

void Registrar::incrementAll() {
    for(auto * obj : regs_)
        obj->index++;
}

Registrar registrar;

int main() {
    const SomeObj obj1 = SomeObj(registrar);
    const SomeObj obj2 = SomeObj(registrar);
    std::cout << obj1.index << ", " << obj2.index << std::endl;

    registrar.incrementAll();
    std::cout << obj1.index << ", " << obj2.index << std::endl;
}


Из конструктора SomeObj протекла неконстантная отсылка к this.
Выведет:
0, 1
1, 2


До С++17 некоторые компиляторы падают во время исполнения, некоторые выдают мусор. ))
Re[103]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 08:42
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


S>>>>>Просто при том, что изначальный вопрос возник о том, что будет в результате применения оптимизации, конкретно NRVO.


V>>>>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


S>>>Так там про NRVO прямым текстом:

что если происходит NRVO


V>>однозначно свзяываешь NRVO и оптимизацию?


S>Так там прямо из названия следует: Named Return Value Optimization.

S>Если что-то называется "оптимизацией", да и ведет себя как "оптимизация", то это оптимизация и есть.

Ну, хз, меня субъективное жонглирование словами не убеждает. Выше по ветке это уже проходили, там implicit create позиционировался как не имеющий отношения к create..

V>>Это не так, NRVO может иметь место и без оптимизации, оптимизация может не применить NRVO.


S>Правильно ли я понимаю, что для вас оптимизация -- это когда флаги компилятору вроде -O1 или -O2 передаются?

S>Так-то компилятор может проводить оптимизации (т.е. устранять избыточный код) и без этих самых флагов, AFAIK.

не то что "для меня", но в том контексте где ты первый раз употребил это слово — я понял именно так, что под "оптимизатором" ты подразумевал ту штуковину, которая существенно преобразует программу всякими разными многочисленными способами с целью увеличения ее оптимальности, то есть, да, "это когда флаги компилятору вроде -O1 или -O2 передаются". Если не правильно понял — пардон, посыпаю голову пеплом.

S>>>Простите, я скипну, поскольку эти 5 пунктов напоминают фокусы из категории "как математически доказать, что 2+2 равно 5". Вот так и здесь люди надергают цитат из стандарта не потрудившись согласовать их друг с другом, а потом выводят вещи, которые не имеют смысла. Простите, если это звучит резко.


V>>К сожалению, это все голословно. Вот если бы ты показал в этих пунктах ошибку, которая покажет несостоятельность сделанного вывода..


S>Так тут уже много-много раз пытались. Вы хотите еще один подход?


S>Чтож, давайте попробуем. Подозрение в наличии UB у некоторых возникает из-за того, что они думают, что константный объект сперва появляется в вызывающей функции, затем модифицируется в вызываемой. И, т.к. в вызывающей функции он константен, то в вызываемой происходит модификация константного объекта.


Нет. Никаких "сперва". Константный объект снаружи и не-константный объект внутри, в случае NRVO это "один и тот же объект" (да, звучит как коллизия, но все же, так написано в стандарте). То есть, наружный константный объект модифицируется внутри функции через неконстантное имя. Это все есть одновременно, а не "сначала/затем"

S>Однако, людям, которые страдают этим подозрением следовало бы доказать и себе, и всем окружающим, что константный объект сперва появляется в вызывающей функции. И что лишь потом к нему обращается вызываемая. А это, мягко говоря, неочевидно.


Вот эта посылка не верна. Объект снаружи и внутри — это по стандарту "один и тот же объект". Его время жизни стартует внутри функции после отработки конструктора. После этого он одновременно и является константным (потому что снаружи задекларирован так) и модифицируется внутри функции.

S>Следовательно, пока не доказано что константный объект начал жить раньше, чем была вызвана функция, мы имеем неконстантный объект внутри вызванной функции. А раз он неконстантный, то его модификация не UB. Потом, в силу NRVO, этот объект не умирает, а остается жить внутри вызывающей функции, но уже как константный. Т.е. константный объект физически появляется в вызывающей функции только после завершения работы вызванной.


S>Поскольку я не знаток стандарта, то подтвердить цитатами все это не смогу. Да и вроде незачем, т.к. УМВР


Если УМВР то и предмета к обсуждению нет)
Re[107]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 08:43
Оценка:
S>>>При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.

σ>>Что значит появляется?


S>Значит появляется. Объяснить эту вещь на еще более тривиальном уровне я не смогу, сорри.


А кто просил на ещё более тривиальном уровне? Объясняй на более корректном.

σ>>Не понел, в (1) два объекта, что ли?


S>Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo


Пруф можно?

S>для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет


В смысле, переменная d не связана ещё ни с каким объектом, или что?

S>>>Если что-то можно модифицировать (и это не mutable поле), то это не константа. Смысл константности в том, что изменять это нельзя.


σ>>Ок. А смысл const object — в другом. Меня интересует const object.


S>Вы в очередной раз отсылаете к этому разделу стандарта. Но там не описан смысл константного объекта.


Что такое "смысл"? Про то, что (и когда) можно/нельзя делать с const object, я тоже ссылки давал.

S>Там дано определение того, что с точки зрения языка считается const object.


Да ладно!

S>>>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.


σ>>Можно конкретнее? Пример модификации и причина UB.


S>Конкретнее я вообще не говорил про модификацию


И это при том, что парой строк выше процитировано «если вы модифицируете свою f»

S>А пример, пожалуйста:

S>
struct S { int i; };

S f();

const S t = f();

S f()
{
  S s;

  s.i = t.i + 42;

  return s;
}


S>При первом вызове f(), который произойдет при инициализации t, вы получите UB, т.к. t не инициализирован


Мы вроде случай NRVO обсуждаем, инициализация кончилась в S s;. Или нет?

S> следовательно, вы обращаетесь к неинициализированному объекту, что есть UB, если меня окончательно не добил склероз.
Re[108]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 08:53
Оценка:
Здравствуйте, σ, Вы писали:

S>>>>При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.


σ>>>Что значит появляется?


S>>Значит появляется. Объяснить эту вещь на еще более тривиальном уровне я не смогу, сорри.


σ>А кто просил на ещё более тривиальном уровне? Объясняй на более корректном.


Корректней некуда. Если вы понимаете только цитаты из стандарта, то, вероятно, вам нужно вот эти пункты (https://timsong-cpp.github.io/cppwp/n4868/basic.life):

The lifetime of an object of type T begins when:
(1.1) storage with the proper alignment and size for type T is obtained, and
(1.2) its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),


Т.е. момент, когда "lifetime" уже "begins".

И да, помнится вы спрашивали меня про что-то вроде "это критерии создания объекта". Вот, пожалуй, и ответ. Вроде бы я и не ошибся.

σ>>>Не понел, в (1) два объекта, что ли?


S>>Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo


σ>Пруф можно?


Пруф на что? На здравый смысл?

S>>для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет


σ>В смысле, переменная d не связана ещё ни с каким объектом, или что?


В смысле что самого понятия d не существует пока инициализация d не завершена. При этом сам объект, который при удачном раскладе станет этим d, уже есть. В некотором промежуточном состоянии. Вот еще одна цитата по приведенной выше ссылке:

[Note 2: In particular, before the lifetime of an object starts and after its lifetime ends there are significant restrictions on the use of the object, as described below, in [class.base.init] and in [class.cdtor]. Also, the behavior of an object under construction and destruction might not be the same as the behavior of an object whose lifetime has started and not ended. [class.base.init] and [class.cdtor] describe the behavior of an object during its periods of construction and destruction. — end note]


S>>>>Если что-то можно модифицировать (и это не mutable поле), то это не константа. Смысл константности в том, что изменять это нельзя.


σ>>>Ок. А смысл const object — в другом. Меня интересует const object.


S>>Вы в очередной раз отсылаете к этому разделу стандарта. Но там не описан смысл константного объекта.


σ>Что такое "смысл"? Про то, что (и когда) можно/нельзя делать с const object, я тоже ссылки давал.


Я не видел таковых.

S>>Там дано определение того, что с точки зрения языка считается const object.


σ>Да ладно!


Представьте себе. Только это, не более.

S>>>>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.


σ>>>Можно конкретнее? Пример модификации и причина UB.


S>>Конкретнее я вообще не говорил про модификацию


σ>И это при том, что парой строк выше процитировано «если вы модифицируете свою f»


Вы не отличаете модифицируете функцию f (т.е. изменение кода) от модификации объекта t?

S>>При первом вызове f(), который произойдет при инициализации t, вы получите UB, т.к. t не инициализирован


σ>Мы вроде случай NRVO обсуждаем, инициализация кончилась в S s;. Или нет?


Нет. Кончилась инициализация s внутри f. Инициализация t еще не начиналась.
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 08:55
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>>Прямо по стандарту компилятору позволяется рассматривать такую ссылку как алиас другой переменной, если ссылка инициализируется именно так — в области видимости ссылаемой переменной/значения.

V>>Не на то смотришь.

V>Наоборот, заставляю тебя смотреть "на то", бо ниже ты опять косячишь в рассуждениях — продолжаем ликбез! ))



V>>>>в исходном примере имеем const std::map<int, int> someDictionary = buildMap();

V>>то есть, имеет место декларация имени someDictionary и объекта типа const std::map<int, int>

V>Не бывает декларации объекта. ))


https://timsong-cpp.github.io/cppwp/basic.def#1.sentence-1

A declaration may (re)introduce one or more names and/or entities into a translation unit.


https://timsong-cpp.github.io/cppwp/basic.pre#3

An entity is a value, object, reference, structured binding, function, enumerator, type, class member, bit-field, template, template specialization, namespace, or pack.


пример использования выражения "декларация объекта": https://timsong-cpp.github.io/cppwp/dcl.pre#def:declaration,object
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 09:02
Оценка:
Здравствуйте, vdimas, Вы писали:

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


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


V>>>Кстате, в исходном примере можно было переделать на ссылку, чтобы ты по мелочам не придирался:

V>>>
V>>>const std::map<int, int> & map = buildMap();
V>>>

V>>>И ничего не изменится, после всех оптимизаций (просто в этом случае будет одна оптимизация копирования, а не две, как в исходном примере).

V>>В этом случае изменится весь кейс.


V>Не-а.



V>>Пропадет NRVO


V>Апочему бы тебе, вместо сотрясения воздуха, предварительно не проверить самостоятельно — пропадается ли NRVO или нет? ))


наверное ты прав, NRVO может и не пропасть. Возвращенный через NRVO объект будет временным, его время жизни продлится ссылкой.. Согласен


V>>пропадет вторая декларация "того же самого объекта"


V>Остаётся.


А вот тут уже никуда не "остается". Декларации объекта теперь нет, вместо объекта теперь декларируется ссылка. Декларация ссылки это не то же самое что декларация объекта так как по декларации объекта определяется его тип, а по декларации ссылки — нет.
Re[104]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 09:02
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>>>однозначно свзяываешь NRVO и оптимизацию?


S>>Так там прямо из названия следует: Named Return Value Optimization.

S>>Если что-то называется "оптимизацией", да и ведет себя как "оптимизация", то это оптимизация и есть.

V>Ну, хз, меня субъективное жонглирование словами не убеждает.


Тут мне остается только повторить, что если что-то называется оптимизацией и ведет себя как оптимизация, так это она и есть.

V>Выше по ветке это уже проходили, там implicit create позиционировался как не имеющий отношения к create..


А он и не имеет. implicit create не создает объектов, он возвращает указатель на объект, для которого лайвтайм будет считаться начатым. Но созданием объектов implicit create не занимается.

V>Нет. Никаких "сперва". Константный объект снаружи и не-константный объект внутри, в случае NRVO это "один и тот же объект" (да, звучит как коллизия, но все же, так написано в стандарте).


Ага.

V>То есть, наружный константный объект модифицируется внутри функции через неконстантное имя. Это все есть одновременно, а не "сначала/затем"


А вот тут нет. Без "сначала" и "затем" нет смысла, мы уходим в слохастическую эквилибристику и споры о том, сколько ангелов уместятся на кончике иглы.

То, что это один и тот же объект не означает, что объект сперва создается в вызывающей функции.
Он как раз создается в вызываемой. Но, за счет NRVO, не умирает там, а продолжает жить в вызвавшей.

Вот и все.

V>Вот эта посылка не верна. Объект снаружи и внутри — это по стандарту "один и тот же объект". Его время жизни стартует внутри функции после отработки конструктора.


А теперь задумайтесь какого именно. И где этот конструктор вызван.

V>Если УМВР то и предмета к обсуждению нет)


Ну так я здесь стал задавать вопросы надеясь на то, что мне с цитатами докажут как я был не прав. Но пока что выходит, что таки был прав
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 09:02
Оценка:
Здравствуйте, vopl, Вы писали:

V>ну так там оно и есть все "одновременно".


Только в случае глобальных переменных и только в случае доступа к переменным в фазе динамической инициализации модуля, где эта инициализация еще не завершена.
Это ДРУГОЕ UB. ))


V>Константный объект, используемый сквозь неконстантное имя, подвергается модификации.


Для локальных констант оно невоспроизводимо, т.к. доступ к константе происходит только после инициализации переменной.
Для глобальных констант после фазы динамической инициализации оно тоже невопроизводимо.


V>в случае NRVO объект внутри и снаружи — это один и тот же объект (σ приводил ссылку на стандарт)


Но внешняя ссылка недоступна программе, т.е. компилятору негде внести неопределённое поведение.


V>следовательно его время жизни уже началось, он уже создан.


Наоборот, время жизни еще не началось.
(у меня такое ощущение, что часть слов вы просто не воспринимаете — слова проходят сквозь вас)

У данных, описанных в модуле, есть две фазы инициализации — статическая и динамическая.
В статической фазе происходит загрузка данных в сегмент данных из соотв.сегмента образа-бинарника.

В статической фазе инициализируются константы времени компиляции, например:
const int i = 42;

(туда же constexpr для вычислимых значений)

В динамической фазе происходит динамическая инициализация, например:
const int i = calcValue();

(если последняя несводима к constexpr)

Что характерно, в статической фазе константе const int i будет присвоено значение 0, а в динамической фазе эта константа будет перезаписана результатом вызова calValue(). Не смущает, ы? ))

То же самое касается конструкторов объектов, если эти конструкторы выполняются только динамически.

Так вот, услышьте уже, что доступ к неинициализированным данным модуля является UB и безо-всякого RVO/NRVO, т.е. это другое UB, нерелевантное обсуждаемому.
И тот якобы пример, который вы привели, он про UB вокруг динамической фазы инициализации. И об этом я сказал твоему союзнику с самого начала, бо вопрос не стоит и выеденного яйца, там всё слишком очевидно. ))

Но после динамической фазы инициализации модуля, либо же, в этой фазе, но с учётом гарантированной последовательности инициализации глобальных переменных модуля, можно избежать упомянутого мною UB, и RVO/NRVO опять на него никак не влияют. Всё.

Тут надо рассуждать не об RVO/NRVO, а об prvalue, которое, начиная с C++17 может не быть материализовано до момента необходимости.
См пример рядом:
http://www.rsdn.org/forum/cpp/8585549.1

Необязательность материализации prvalue — более общее допущение, которое способно даже удалять локальные промежуточные переменные, протягивая "сквозь них" prvalue в процессе оптимизации бинарника. Но! мы можем рассуждать исключительно и только о семантике, описанной в коде, как будто нет никаких допущений относительно необязательности материализации prvalue, нет никаких RVO/NRVO и прочих трюков. Именно поэтому для prvalue всё еще требуются конструкторы копирования, которых в конечном образе может и не быть за ненадобностью — они нужны исключительно для описания исходной семантики кода, которая гарантируется компилятором, с учётом замечания про побочные эффекты.

По ссылке приведён как раз побочный эффект конструктора, где this протекает "куда-то еще", в какой-то другой контекст, необнаруживаемый компилятором при компиляции текущего модуля.
(registrar по ссылке мог быть объявлен в другом модуле)
Re[103]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 09:10
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>>Или собственное непонимание, ведь стандарт описан не для домохозяек, а для специалистов с неким ненулевым бэкграундом.

V>>у вас тут секта грубиянов чтоли?

V>Дык, вы ж не показали понимание прочитанного в стандарте.

Ну так это же не повод навешивать ярлыки. Если есть возможность — укажи на ошибку конкретно, я только благодарен буду

V>Давай я покажу тебе суть того UB, на который вы ссылаетесь, где этот UB можно получить безо-всяких реинтерпретаций/хаков:

V>
V>#include <vector>
V>#include <iostream>

V>class SomeObj;

V>class Registrar {
V>    std::vector<SomeObj*> regs_;
V>    int index {};

V>public:
V>    void registerObj(SomeObj * obj);
V>    void incrementAll();
V>};

V>class SomeObj {
V>public:
V>    SomeObj(Registrar & reg) {
V>        reg.registerObj(this);
V>    }

V>    int index {};
V>};

V>void Registrar::registerObj(SomeObj * obj) {
    obj->>index = index++;
V>    regs_.push_back(obj);
V>}

V>void Registrar::incrementAll() {
V>    for(auto * obj : regs_)
        obj->>index++;
V>}

V>Registrar registrar;

V>int main() {
V>    const SomeObj obj1 = SomeObj(registrar);
V>    const SomeObj obj2 = SomeObj(registrar);
V>    std::cout << obj1.index << ", " << obj2.index << std::endl;

V>    registrar.incrementAll();
V>    std::cout << obj1.index << ", " << obj2.index << std::endl;
V>}
V>


V>Из конструктора SomeObj протекла неконстантная отсылка к this.

V>Выведет:
V>
V>0, 1
V>1, 2
V>


V>До С++17 некоторые компиляторы падают во время исполнения, некоторые выдают мусор. ))


Эта суть понятна в полной мере. По прежнему имею мнение что сабжевый "гипотетический UB" имеет такую же природу, но несколько другой механизм активации
Re[100]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 09:26
Оценка: +2
Здравствуйте, σ, Вы писали:

σ>>>И что «lifetime»? Он начинается внутри функции, после инициализации result.

BFE>>Когда начинается lifetime объекта someDictionary ? Тогда, когда заканчивается конструирование объекта.
σ>Ну. При NRVO, оно заканчивается на std::map<int, int> result;.

Нет, конечно. Даже при NRVO вычисление значения выражения buildMap() должно быть выполнено до начала инициализации someDictionary. Это следует из описания sequenced before.
А пока вычисление выражения buildMap() не закончилось, время жизни константного объекта не началось:

The lifetime of an object of type T begins when: ... its initialization (if any) is complete

Запрет на модификацию константного объекта относится только ко времени жизни:

Any attempt to modify a const object during its lifetime results in undefined behavior.

Ну а так, как время жизни константного объекта ещё не началось, то изменять его можно.
Нет тут никакого UB.

BFE>>В выражении const std::map<int, int> someDictionary = buildMap(); вызов buildMap() sequenced before инициализации someDictionary, а значит значение для инициализации должно быть получено до начала lifetime объекта someDictionary. А до этих пор константный объект можно модифицировать.


σ>Получается, result.insert(42, 43); — UB, т.к. после старта лайфтайма?

Нет.
Такое впечатление, что вы не читает, что я пишу.

σ>Или объект сначала вроде как создаётся константным (const std::map<int, int> someDictionary), но потом становится неконстантным (std::map<int, int> result;), а опять константным не становится, и его можно менять даже после const std::map<int, int> someDictionary = buildMap();?

Близко нет.
И каждый день — без права на ошибку...
Re[109]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 09:27
Оценка:
S>>>>>При завершении работы конструктора в точке вызова как раз появляется объект, который уже будет константным.

σ>>>>Что значит появляется?


S>>>Значит появляется. Объяснить эту вещь на еще более тривиальном уровне я не смогу, сорри.


σ>>А кто просил на ещё более тривиальном уровне? Объясняй на более корректном.


S>Корректней некуда. Если вы понимаете только цитаты из стандарта, то, вероятно, вам нужно вот эти пункты (https://timsong-cpp.github.io/cppwp/n4868/basic.life):

S>

The lifetime of an object of type T begins when:
(1.1) storage with the proper alignment and size for type T is obtained, and
(1.2) its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),


S>Т.е. момент, когда "lifetime" уже "begins".


S>И да, помнится вы спрашивали меня про что-то вроде "это критерии создания объекта". Вот, пожалуй, и ответ. Вроде бы я и не ошибся.


Я тоже вижу что не ошибся в своих подозрениях что ты не знаешь разницы между созданием объекта и началом времени жизни объекта.
Параграф про lifetime start описывает как начинается lifetime уже существующего (созданного) объекта, а не про то, как объект создаётся.

σ>>>>Не понел, в (1) два объекта, что ли?


S>>>Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo


σ>>Пруф можно?


S>Пруф на что? На здравый смысл?


Ну если ты хочешь переходить на такой детсадовский уровень, то ок: здравый смысл говорит что появляется объект типа const demo.

S>>>для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет


σ>>В смысле, переменная d не связана ещё ни с каким объектом, или что?


S>В смысле что самого понятия d не существует пока инициализация d не завершена.


Что такое «самого понятия d не существует»? Ты можешь перестать выражаться всякими размытыми фразами? Что за «самоё понятие d»?

S>При этом сам объект, который при удачном раскладе станет этим d, уже есть. В некотором промежуточном состоянии. Вот еще одна цитата по приведенной выше ссылке:

S>

[Note 2: In particular, before the lifetime of an object starts and after its lifetime ends there are significant restrictions on the use of the object, as described below, in [class.base.init] and in [class.cdtor]. Also, the behavior of an object under construction and destruction might not be the same as the behavior of an object whose lifetime has started and not ended. [class.base.init] and [class.cdtor] describe the behavior of an object during its periods of construction and destruction. — end note]


И она тут к чему? В ней написано что-то про самоё понятие d?

S>>>>>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.


σ>>>>Можно конкретнее? Пример модификации и причина UB.


S>>>Конкретнее я вообще не говорил про модификацию


σ>>И это при том, что парой строк выше процитировано «если вы модифицируете свою f»


S>Вы не отличаете модифицируете функцию f (т.е. изменение кода) от модификации объекта t?


Пора бы уже от выходных отойти. Или у тебя уже permanent damage?

S>>>При первом вызове f(), который произойдет при инициализации t, вы получите UB, т.к. t не инициализирован


σ>>Мы вроде случай NRVO обсуждаем, инициализация кончилась в S s;. Или нет?


S>Нет. Кончилась инициализация s внутри f. Инициализация t еще не начиналась.


Т.е. ты всё-таки не отличаешь объекты от переменных? Или что?
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 09:37
Оценка: :)
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>>>однозначно свзяываешь NRVO и оптимизацию?


S>>>Так там прямо из названия следует: Named Return Value Optimization.

S>>>Если что-то называется "оптимизацией", да и ведет себя как "оптимизация", то это оптимизация и есть.

V>>Ну, хз, меня субъективное жонглирование словами не убеждает.


S>Тут мне остается только повторить, что если что-то называется оптимизацией и ведет себя как оптимизация, так это она и есть.


V>>Выше по ветке это уже проходили, там implicit create позиционировался как не имеющий отношения к create..


S>А он и не имеет. implicit create не создает объектов, он возвращает указатель на объект, для которого лайвтайм будет считаться начатым. Но созданием объектов implicit create не занимается.


https://timsong-cpp.github.io/cppwp/intro.object#1.sentence-2

An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]).


например, operator new создает объект посредством этого самого implicitly creates
https://timsong-cpp.github.io/cppwp/intro.object#13.sentence-3

Any implicit or explicit invocation of a function named operator new or operator new[] implicitly creates objects in the returned region of storage and returns a pointer to a suitable created object.



V>>Нет. Никаких "сперва". Константный объект снаружи и не-константный объект внутри, в случае NRVO это "один и тот же объект" (да, звучит как коллизия, но все же, так написано в стандарте).


S>Ага.


V>>То есть, наружный константный объект модифицируется внутри функции через неконстантное имя. Это все есть одновременно, а не "сначала/затем"


S>А вот тут нет. Без "сначала" и "затем" нет смысла, мы уходим в слохастическую эквилибристику и споры о том, сколько ангелов уместятся на кончике иглы.

ангелы

S>То, что это один и тот же объект не означает, что объект сперва создается в вызывающей функции.

S>Он как раз создается в вызываемой. Но, за счет NRVO, не умирает там, а продолжает жить в вызвавшей.

S>Вот и все.


Именно так) Он создается в функции, затем просто продолжает жить вне ее после NRVO

V>>Вот эта посылка не верна. Объект снаружи и внутри — это по стандарту "один и тот же объект". Его время жизни стартует внутри функции после отработки конструктора.


S>А теперь задумайтесь какого именно. И где этот конструктор вызван.


Отработает конструктор не-константного типа, внутри функции

V>>Если УМВР то и предмета к обсуждению нет)


S>Ну так я здесь стал задавать вопросы надеясь на то, что мне с цитатами докажут как я был не прав. Но пока что выходит, что таки был прав


С цитатами — я приводил выше 5 пунктов, в них цитаты не прямо там вшиты, но есть отсылки к цитатам. Эти 5 пунктов все еще актуальны и не опровергнуты
Re[110]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 09:38
Оценка:
Здравствуйте, σ, Вы писали:

S>>Корректней некуда. Если вы понимаете только цитаты из стандарта, то, вероятно, вам нужно вот эти пункты (https://timsong-cpp.github.io/cppwp/n4868/basic.life):

S>>

The lifetime of an object of type T begins when:
σ>(1.1) storage with the proper alignment and size for type T is obtained, and
σ>(1.2) its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),


S>>Т.е. момент, когда "lifetime" уже "begins".


S>>И да, помнится вы спрашивали меня про что-то вроде "это критерии создания объекта". Вот, пожалуй, и ответ. Вроде бы я и не ошибся.


σ>Я тоже вижу что не ошибся в своих подозрениях что ты не знаешь разницы между созданием объекта и началом времени жизни объекта.

σ>Параграф про lifetime start описывает как начинается lifetime уже существующего (созданного) объекта, а не про то, как объект создаётся.

Замечательно, но пока вы оцениваете мои знания вы никаких доводов в пользу своей точки зрения не приводите.

σ>>>>>Не понел, в (1) два объекта, что ли?


S>>>>Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo


σ>>>Пруф можно?


S>>Пруф на что? На здравый смысл?


σ>Ну если ты хочешь переходить на такой детсадовский уровень, то ок: здравый смысл говорит что появляется объект типа const demo.


Появляется. Не вижу здесь противоречий с тем, что я сказал. В чем предмет спора?

S>>>>для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет


σ>>>В смысле, переменная d не связана ещё ни с каким объектом, или что?


S>>В смысле что самого понятия d не существует пока инициализация d не завершена.


σ>Что такое «самого понятия d не существует»? Ты можешь перестать выражаться всякими размытыми фразами? Что за «самоё понятие d»?


А вы попробуйте читать что вам пишут. У вас в коде есть строка:
void f() {
  const demo d;
  ...
}

Так вот, пользоваться d вы сможете только когда завершится его создание (т.е. выделение места и инициализация). До этого момента у вас в f() никакого d еще нет. Вот когда создание d завершится успешно, тогда d в f у вас есть. А до того нет. Вообще.

S>>При этом сам объект, который при удачном раскладе станет этим d, уже есть. В некотором промежуточном состоянии. Вот еще одна цитата по приведенной выше ссылке:

S>>

[Note 2: In particular, before the lifetime of an object starts and after its lifetime ends there are significant restrictions on the use of the object, as described below, in [class.base.init] and in [class.cdtor]. Also, the behavior of an object under construction and destruction might not be the same as the behavior of an object whose lifetime has started and not ended. [class.base.init] and [class.cdtor] describe the behavior of an object during its periods of construction and destruction. — end note]


σ>И она тут к чему? В ней написано что-то про самоё понятие d?


В ней написано про момент, когда объект уже "типа есть" но лайфтайм для него начатым еще не считается. А это как раз имеет прямое отношение к d, которого еще нет, пока его инициализация не завершилась (хотя объект типа demo уже конструируется и у него работает конструктор).

S>>>>>>Более того, если вы модифицируете свою f так, чтобы там было обращение к t, то вы получите UB.σ>>>Мы вроде случай NRVO обсуждаем, инициализация кончилась в S s;. Или нет?


S>>Нет. Кончилась инициализация s внутри f. Инициализация t еще не начиналась.


σ>Т.е. ты всё-таки не отличаешь объекты от переменных? Или что?


Вы хотите перейти на обсуждение персоналий? Или мы таки продолжим говорить про происходящее в C++?
Re[101]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 09:49
Оценка:
σ>>>>И что «lifetime»? Он начинается внутри функции, после инициализации result.
BFE>>>Когда начинается lifetime объекта someDictionary ? Тогда, когда заканчивается конструирование объекта.
σ>>Ну. При NRVO, оно заканчивается на std::map<int, int> result;.

BFE>Нет, конечно. Даже при NRVO вычисление значения выражения buildMap() должно быть выполнено до начала инициализации someDictionary. Это следует из описания sequenced before.


Да ради бога, пусть sequenced before.
Только вот sequenced before никак не отменят, что при NRVO someDictionary обозначает тот же объект, что и result, как описано в https://timsong-cpp.github.io/cppwp/n4868/class.copy.elision#1.sentence-2

BFE>А пока вычисление выражения buildMap() не закончилось, время жизни константного объекта не началось:

BFE>

The lifetime of an object of type T begins when: ... its initialization (if any) is complete


Ну и какая инициализация для этого объекта должа быть complete? Первая (std::map<int, int> result;) или последняя (которая для someDictionary)?

BFE>Запрет на модификацию константного объекта относится только ко времени жизни:

BFE>

Any attempt to modify a const object during its lifetime results in undefined behavior.

BFE>Ну а так, как время жизни константного объекта ещё не началось, то изменять его можно.
BFE>Нет тут никакого UB.

Раз время жизни объекта не началось, то result.insert(42, 43); — вызов метода на объекте до начала времени жизни? Тогда получается UB есть.

BFE>>>В выражении const std::map<int, int> someDictionary = buildMap(); вызов buildMap() sequenced before инициализации someDictionary, а значит значение для инициализации должно быть получено до начала lifetime объекта someDictionary. А до этих пор константный объект можно модифицировать.


σ>>Получается, result.insert(42, 43); — UB, т.к. после старта лайфтайма?

BFE>Нет.
BFE>Такое впечатление, что вы не читает, что я пишу.

Аналогично.

σ>>Или объект сначала вроде как создаётся константным (const std::map<int, int> someDictionary), но потом становится неконстантным (std::map<int, int> result;), а опять константным не становится, и его можно менять даже после const std::map<int, int> someDictionary = buildMap();?

BFE>Близко нет.
Ты наверное опечатался когда хотел написать «ближе нет»?
  Скрытый текст
По крайней мере кое-то в CWG согласен, что, видимо, согласно текущему тексту стандарта, такое описание самое (формально) корректное .
В общем, я спалил ответ на свой вопрос, по крайней мере соответствующий стандарту буквально (насколько стандарт тут дефектен, это отдельный разговор), а ты даже не понял.
Re[106]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 09:55
Оценка:
Здравствуйте, vopl, Вы писали:

V>>>Выше по ветке это уже проходили, там implicit create позиционировался как не имеющий отношения к create..


S>>А он и не имеет. implicit create не создает объектов, он возвращает указатель на объект, для которого лайвтайм будет считаться начатым. Но созданием объектов implicit create не занимается.


V>https://timsong-cpp.github.io/cppwp/intro.object#1.sentence-2

V>

An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]).


Ну вот еще раз люди читают стандарт и теряют из виду смысл происходящего (это как за деревьями не видеть леса).

А смысл такой: в C++ объекты должны быть созданы (т.е. у них должен начаться lifetime) видимым для компилятора образом. Если появляется указатель на что-то, что компилятор не может определить как корректно созданный объект (с начатым lifetime), то компилятор волен сотворить разное. При этом в реальной жизни случаются ситуации, когда объекты создаются невидимым для компилятора образом (скажем, посредством вызова calloc, посредством чтения с диска в память или посредством отображения из разделяемой памяти). И тогда возникает вопрос как указать компилятору, что у нас корректный объект, а не херня какая-то.

И вот для решения этой проблемы (причем в большей степени для решения проблемы того, как описать это в стандарте) и сделали термин implicitly creates. Т.е. применение некоторых конструкций (вроде каста возвращенного calloc-ом результата к указателю на некий T) якобы создает объект типа T.

Хотя, на самом деле, здесь нет никакого создания. Создание (а именно выделение места и инициализация этого места должным образом) лежит на пользователе. Т.е., по факту, implicitly creates означает, что пользователь сделал все вручную, но затем компилятор согласился считать полученный пользователем указатель валидным указателем на объект с начатым lifetime.

Вот, собственно, и все.

Именно так и следует объяснять происходящее обычным разработчикам. Чтобы они понимали, что создание объекта через new -- это одно. Создание объекта на стеке -- другое. Легитимизация указателя на содержимое объекта полученное через разделяемую память -- третье. Хотя с точки зрения текста стандарта это все типа "creates".

Вот если бы происходящее в языке C++ объясняли такими простыми словами, лично моя жизнь была бы сильно проще.

S>>Вот и все.


V>Именно так) Он создается в функции, затем просто продолжает жить вне ее после NRVO


Если вы согласны с этим, то у вас просто нет константного объекта, который начал жить раньше и который мы якобы пытаемся модифицировать внутри. Т.е. и нет предмета для спора.

V>С цитатами — я приводил выше 5 пунктов, в них цитаты не прямо там вшиты, но есть отсылки к цитатам. Эти 5 пунктов все еще актуальны и не опровергнуты


Еще раз повторюсь про аналогию с доказательством что 2+2=5.
Re[111]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 10:13
Оценка:
σ>>Я тоже вижу что не ошибся в своих подозрениях что ты не знаешь разницы между созданием объекта и началом времени жизни объекта.
σ>>Параграф про lifetime start описывает как начинается lifetime уже существующего (созданного) объекта, а не про то, как объект создаётся.

S>Замечательно, но пока вы оцениваете мои знания вы никаких доводов в пользу своей точки зрения не приводите.


Это не моя точка зрения. Это стандарт. Поищи по слову created, например.

σ>>>>>>Не понел, в (1) два объекта, что ли?


S>>>>>Нет. Просто точка (1) она не точка, это временной отрезок, который начинается, длится и заканчивается. Когда он начинается в программе появляется объект типа demo


σ>>>>Пруф можно?


S>>>Пруф на что? На здравый смысл?


σ>>Ну если ты хочешь переходить на такой детсадовский уровень, то ок: здравый смысл говорит что появляется объект типа const demo.


S>Появляется. Не вижу здесь противоречий с тем, что я сказал. В чем предмет спора?


Не прикидывайся. Появляется только объект типа const demo. Это не только здравому смыслу соответствует.

S>>>>>для которого вызывается конструктор, когда этот отрезок завершается этот самый объект становится доступным внутри f() под именем d. Но пока этот отрезок не завершился, внутри f() объекта d еще нет


σ>>>>В смысле, переменная d не связана ещё ни с каким объектом, или что?


S>>>В смысле что самого понятия d не существует пока инициализация d не завершена.


σ>>Что такое «самого понятия d не существует»? Ты можешь перестать выражаться всякими размытыми фразами? Что за «самоё понятие d»?


S>А вы попробуйте читать что вам пишут. У вас в коде есть строка:

S>
void f() {
 const demo d;
  ...
}

S>Так вот, пользоваться d вы сможете только когда завершится его создание (т.е. выделение места и инициализация). До этого момента у вас в f() никакого d еще нет. Вот когда создание d завершится успешно, тогда d в f у вас есть. А до того нет. Вообще.

Т.е. ты всё это время пытался выродить мысль, что внутри f lookup для имени d найдёт переменную d только в точке программы после const demo d?
А зачем ты это пытался сказать? Как это влияет на тип объекта?

σ>>И она тут к чему? В ней написано что-то про самоё понятие d?


S>В ней написано про момент, когда объект уже "типа есть" но лайфтайм для него начатым еще не считается.


И какого же типа этот объект?

S>А это как раз имеет прямое отношение к d, которого еще нет, пока его инициализация не завершилась


ЧТО ЗНАЧИТ ЧТО d ЕЩЁ НЕТ?
Как переменная, d "есть" ещё без всяких инициализаций и вообще без выполнения программы, "синтаксически": в теле f есть переменная d.

S>Вы хотите перейти на обсуждение персоналий? Или мы таки продолжим говорить про происходящее в C++?


Продолжим?!!
МЫ почти не начинали говорить о C++. В смысле, я-то с самого начала говорил, а ты десятки сообщений вываливал своё личное мнение/«эмпирический опыт» что, по-твоему, надо считать константным объектом и проч. подобное.
Re[112]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 10:29
Оценка:
Здравствуйте, σ, Вы писали:

σ>Это не моя точка зрения. Это стандарт. Поищи по слову created, например.


Это уже заход на какой-то N-ый круг.

σ>Не прикидывайся. Появляется только объект типа const demo. Это не только здравому смыслу соответствует.


Только вот фокус в том, что пока инициализация const demo d не завершилась, есть объект типа demo.

σ>Т.е. ты всё это время пытался выродить мысль, что внутри f lookup для имени d найдёт переменную d только в точке программы после const demo d?


Нет, про lookup имен я вообще ничего не говорил. Речь про то, когда объекты начинают жить и в каком виде.

σ>Как это влияет на тип объекта?


Тем, что внутри конструктора мы имеем demo. После его успешного завершения уже const demo.

S>>В ней написано про момент, когда объект уже "типа есть" но лайфтайм для него начатым еще не считается.


σ>И какого же типа этот объект?


Внутри конструктора -- demo.

S>>Вы хотите перейти на обсуждение персоналий? Или мы таки продолжим говорить про происходящее в C++?


σ>Продолжим?!!

σ>МЫ почти не начинали говорить о C++. В смысле, я-то с самого начала говорил, а ты десятки сообщений вываливал своё личное мнение/«эмпирический опыт» что, по-твоему, надо считать константным объектом и проч. подобное.

Ну как-то так получается, что эмпирический опыт исходя из которого я здесь привожу примеры, основан на C++. Следовательно я говорю про C++.
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 10:29
Оценка:
Здравствуйте, vopl, Вы писали:

V>>До С++17 некоторые компиляторы падают во время исполнения, некоторые выдают мусор. ))

V>Эта суть понятна в полной мере.

Вывод был
0, 1
1, 2


Хотя компилятор мог бы закешировать значения index в регистрах или вообще расположить экземпляры объектов в регистрах, ведь их размер это позволяет.
Т.е., программа могла выдать и
0, 1
1, 2

и
0, 0
0, 0

и просто упасть, если бы компилятор "не обратил внимание" на протекающий this.


V>По прежнему имею мнение что сабжевый "гипотетический UB" имеет такую же природу, но несколько другой механизм активации


Сабжевый ваш UB другой, имеет природу недоинициализированных глобальных переменных в динамической фазе инициализации.
Это очень старый UB, который живёт с самых первых версий С++, когда о RVO еще не слышали. ))

Этот ваш UB легко воспроизводим и без константности.
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 10:29
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>ну так там оно и есть все "одновременно".


V>Только в случае глобальных переменных и только в случае доступа к переменным в фазе динамической инициализации модуля, где эта инициализация еще не завершена.

V>Это ДРУГОЕ UB. ))

глобальность непричем, вот такой кейс имеет то же самое "гипотетическое UB"

struct T {int m;};

T make()
{
    T inner;
    inner.m = 220;
    return inner;
}

int main()
{
    const T outer = make();

    return 0;
}



V>>Константный объект, используемый сквозь неконстантное имя, подвергается модификации.


V>Для локальных констант оно невоспроизводимо, т.к. доступ к константе происходит только после инициализации переменной.

не важно когда происходит доступ. Тип объекта, определяемый декларацией потенциально является константным. На этой основе компилятор может делать всякие предположения относительно доступа к этому объекту. И объект после своего создания/инициализации используется как мутабельный.

вот так оно может быть развернуто компилятором

struct T {int m;};

int main()
{
    count T outer{};// только конструктор будет от неконстантного имени. Да я знаю что конструктору плевать, просто отмечаю сей факт

    T& inner = const_cast<T&>(outer);
    inner.m = 220;

    return 0;
}



V>Для глобальных констант после фазы динамической инициализации оно тоже невопроизводимо.



V>>в случае NRVO объект внутри и снаружи — это один и тот же объект (σ приводил ссылку на стандарт)


V>Но внешняя ссылка недоступна программе, т.е. компилятору негде внести неопределённое поведение.



V>>следовательно его время жизни уже началось, он уже создан.


V>Наоборот, время жизни еще не началось.

V>(у меня такое ощущение, что часть слов вы просто не воспринимаете — слова проходят сквозь вас)

наверное да.. Я игнорирую тезисы которые просто высказываются в утвердительной форме, без обоснований

V>У данных, описанных в модуле, есть две фазы инициализации — статическая и динамическая.

V>В статической фазе происходит загрузка данных в сегмент данных из соотв.сегмента образа-бинарника.

V>В статической фазе инициализируются константы времени компиляции, например:

V>
V>const int i = 42;
V>

V>(туда же constexpr для вычислимых значений)

V>В динамической фазе происходит динамическая инициализация, например:

V>
V>const int i = calcValue();
V>

V>(если последняя несводима к constexpr)

V>Что характерно, в статической фазе константе const int i будет присвоено значение 0, а в динамической фазе эта константа будет перезаписана результатом вызова calValue(). Не смущает, ы? ))


это все не важно

V>То же самое касается конструкторов объектов, если эти конструкторы выполняются только динамически.


V>Так вот, услышьте уже, что доступ к неинициализированным данным модуля является UB и безо-всякого RVO/NRVO, т.е. это другое UB, нерелевантное обсуждаемому.


Услышал. Сабжевое "гипотетическое UB" — не про доступ к неинициализированным данным. В кейсе с "гипотетическим UB" все инициализировано до использования.

V>И тот якобы пример, который вы привели, он про UB вокруг динамической фазы инициализации. И об этом я сказал твоему союзнику с самого начала, бо вопрос не стоит и выеденного яйца, там всё слишком очевидно. ))


Нет. Это был пример в котором объявлен константный объект, он создан/инициализирован и потом с ним идет работа как не с константным, что есть UB.

V>Но после динамической фазы инициализации модуля, либо же, в этой фазе, но с учётом гарантированной последовательности инициализации глобальных переменных модуля, можно избежать упомянутого мною UB, и RVO/NRVO опять на него никак не влияют. Всё.


Не в ту сторону все.

V>Тут надо рассуждать не об RVO/NRVO, а об prvalue, которое, начиная с C++17 может не быть материализовано до момента необходимости.

V>См пример рядом:
V>http://www.rsdn.org/forum/cpp/8585549.1

V>Необязательность материализации prvalue — более общее допущение, которое способно даже удалять локальные промежуточные переменные, протягивая "сквозь них" prvalue в процессе оптимизации бинарника. Но! мы можем рассуждать исключительно и только о семантике, описанной в коде, как будто нет никаких допущений относительно необязательности материализации prvalue, нет никаких RVO/NRVO и прочих трюков. Именно поэтому для prvalue всё еще требуются конструкторы копирования, которых в конечном образе может и не быть за ненадобностью — они нужны исключительно для описания исходной семантики кода, которая гарантируется компилятором, с учётом замечания про побочные эффекты.


V>По ссылке приведён как раз побочный эффект конструктора, где this протекает "куда-то еще", в какой-то другой контекст, необнаруживаемый компилятором при компиляции текущего модуля.

V>(registrar по ссылке мог быть объявлен в другом модуле)

Пример посмотрел, понял, там отписал. В нем другой способ инициирования записи в константный объект, в общем, этот пример не принимается как полный, но очень хорошо показывает запись в константный объект, которая есть и в кейсе с "гипотетическим UB"
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 10:35
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>>До С++17 некоторые компиляторы падают во время исполнения, некоторые выдают мусор. ))

V>>Эта суть понятна в полной мере.

V>Вывод был

V>
V>0, 1
V>1, 2
V>


V>Хотя компилятор мог бы закешировать значения index в регистрах или вообще расположить экземпляры объектов в регистрах, ведь их размер это позволяет.

V>Т.е., программа могла выдать и
V>
V>0, 1
V>1, 2
V>

V>и
V>
V>0, 0
V>0, 0
V>

V>и просто упасть, если бы компилятор "не обратил внимание" на протекающий this.


V>>По прежнему имею мнение что сабжевый "гипотетический UB" имеет такую же природу, но несколько другой механизм активации


V>Сабжевый ваш UB другой, имеет природу недоинициализированных глобальных переменных в динамической фазе инициализации.

V>Это очень старый UB, который живёт с самых первых версий С++, когда о RVO еще не слышали. ))

V>Этот ваш UB легко воспроизводим и без константности.


Да штош такое то) Сабжевый наш UB — НЕ имеет природу недоинициализированных глобальных переменных в динамической фазе инициализации. Он про другое. Не про погрешности в инициализации. Он про запист в гипотетически константный, нормально проинициализированный объект.
Re[102]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 10:42
Оценка:
Здравствуйте, σ, Вы писали:

σ>Только вот sequenced before никак не отменят, что при NRVO someDictionary обозначает тот же объект, что и result, как описано в https://timsong-cpp.github.io/cppwp/n4868/class.copy.elision#1.sentence-2

Здесь ссылка на sequenced before только для того, чтобы показать, что время жизни someDictionary ещё не началось.

BFE>>А пока вычисление выражения buildMap() не закончилось, время жизни константного объекта не началось:

BFE>>

σ>The lifetime of an object of type T begins when: ... its initialization (if any) is complete

σ>Ну и какая инициализация для этого объекта должа быть complete? Первая (std::map<int, int> result;) или последняя (которая для someDictionary)?
Последняя. Та, которая пропускается. Вы видимо не понимаете, что опущение (omitter) операции не отменяет момент старта времени жизни константного объекта.

BFE>>Запрет на модификацию константного объекта относится только ко времени жизни:

BFE>>

σ>Any attempt to modify a const object during its lifetime results in undefined behavior.

BFE>>Ну а так, как время жизни константного объекта ещё не началось, то изменять его можно.
BFE>>Нет тут никакого UB.

σ>Раз время жизни объекта не началось, то result.insert(42, 43); — вызов метода на объекте до начала времени жизни? Тогда получается UB есть.

Разумеется это не так. Объект может изменятся внутри конструктора, т.е. до начала lifetime.

σ>>>Или объект сначала вроде как создаётся константным (const std::map<int, int> someDictionary), но потом становится неконстантным (std::map<int, int> result;), а опять константным не становится, и его можно менять даже после const std::map<int, int> someDictionary = buildMap();?

BFE>>Близко нет.
σ>Ты наверное опечатался когда хотел написать «ближе нет»?
Нет.

σ>По крайней мере кое-то в CWG согласен, что, видимо, согласно текущему тексту стандарта, такое описание самое (формально) корректное .

σ>В общем, я спалил ответ на свой вопрос, по крайней мере соответствующий стандарту буквально (насколько стандарт тут дефектен, это отдельный разговор), а ты даже не понял.
апелляция к авторитету
Вы ошибаетесь и ваш авторитет ошибается. Я же вас с самого начала предупреждал, что попытка описания на естественном языке формального поведения однозначно приведёт к проблемам толкования.
И ваше описание формально не корректно. Если формально, то константный объект не может становится неконстантным: A const object is an object of type const T. Другое дело, что есть периоды существования объекта (не путайте со временем жизни), когда константный объект можно изменять.
А то, что вы тут описываете, это неформальное описание, которое даёт тот же видимый эффект, но верным от этого не становится.
И каждый день — без права на ошибку...
Re[107]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 10:48
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>>>Выше по ветке это уже проходили, там implicit create позиционировался как не имеющий отношения к create..


S>>>А он и не имеет. implicit create не создает объектов, он возвращает указатель на объект, для которого лайвтайм будет считаться начатым. Но созданием объектов implicit create не занимается.


V>>https://timsong-cpp.github.io/cppwp/intro.object#1.sentence-2

V>>

An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]).


S>Ну вот еще раз люди читают стандарт и теряют из виду смысл происходящего (это как за деревьями не видеть леса).


S>А смысл такой: в C++ объекты должны быть созданы (т.е. у них должен начаться lifetime) видимым для компилятора образом. Если появляется указатель на что-то, что компилятор не может определить как корректно созданный объект (с начатым lifetime), то компилятор волен сотворить разное. При этом в реальной жизни случаются ситуации, когда объекты создаются невидимым для компилятора образом (скажем, посредством вызова calloc, посредством чтения с диска в память или посредством отображения из разделяемой памяти). И тогда возникает вопрос как указать компилятору, что у нас корректный объект, а не херня какая-то.


S>И вот для решения этой проблемы (причем в большей степени для решения проблемы того, как описать это в стандарте) и сделали термин implicitly creates. Т.е. применение некоторых конструкций (вроде каста возвращенного calloc-ом результата к указателю на некий T) якобы создает объект типа T.


S>Хотя, на самом деле, здесь нет никакого создания. Создание (а именно выделение места и инициализация этого места должным образом) лежит на пользователе. Т.е., по факту, implicitly creates означает, что пользователь сделал все вручную, но затем компилятор согласился считать полученный пользователем указатель валидным указателем на объект с начатым lifetime.


S>Вот, собственно, и все.


S>Именно так и следует объяснять происходящее обычным разработчикам. Чтобы они понимали, что создание объекта через new -- это одно. Создание объекта на стеке -- другое. Легитимизация указателя на содержимое объекта полученное через разделяемую память -- третье. Хотя с точки зрения текста стандарта это все типа "creates".


S>Вот если бы происходящее в языке C++ объясняли такими простыми словами, лично моя жизнь была бы сильно проще.


Обычные разработчики тут не при чем. Я конечно могу начать придумывать что такое "создание объекта", и может быть даже моя придумка совпадет с твоей, но это будет лишь субъектив, с большой вероятностью отличающийся от реалий. Если честно — мне становится немного не по себе от сложившейся ситуации. Приведена выдержка из стандарта, в которой определяется что суть есть "object creation". И как после нее можно заявлять о потере смысла? Она и определяет смысл. Она есть смысл. Какой еще lifetime Приведено оригинальное определение. В нем нет ни слова про lifetime. Думаю далее нет смысла продолжать
Re[113]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 10:48
Оценка:
σ>>Это не моя точка зрения. Это стандарт. Поищи по слову created, например.

S>Это уже заход на какой-то N-ый круг.


Т.е. ты уже N кругов ищешь по слову created (ну и читаешь, что нашёл, естественно), но так и не понял разницу между an object is created и object lifetime starts?

σ>>Не прикидывайся. Появляется только объект типа const demo. Это не только здравому смыслу соответствует.


S>Только вот фокус в том, что пока инициализация const demo d не завершилась, есть объект типа demo.


Пруф?

σ>>Т.е. ты всё это время пытался выродить мысль, что внутри f lookup для имени d найдёт переменную d только в точке программы после const demo d?


S>Нет, про lookup имен я вообще ничего не говорил. Речь про то, когда объекты начинают жить и в каком виде.


σ>>Как это влияет на тип объекта?


S>Тем, что внутри конструктора мы имеем demo. После его успешного завершения уже const demo.


Пруф?

S>>>В ней написано про момент, когда объект уже "типа есть" но лайфтайм для него начатым еще не считается.


σ>>И какого же типа этот объект?


S>Внутри конструктора -- demo.


Пруф?

S>Ну как-то так получается, что эмпирический опыт исходя из которого я здесь привожу примеры, основан на C++.


Нет, он не основан на C++. Твой эмпирический опыт — это максимум взаимодействие с некоторыми т.н. реализациями C++.
Ну и, самое главное, ты ведь приводишь не свой опыт, а вещаешь свои кривые его интерпретации.
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 10:48
Оценка:
Здравствуйте, vopl, Вы писали:

V>Нет. Никаких "сперва". Константный объект снаружи и не-константный объект внутри, в случае NRVO это "один и тот же объект" (да, звучит как коллизия, но все же, так написано в стандарте). То есть, наружный константный объект модифицируется внутри функции через неконстантное имя. Это все есть одновременно, а не "сначала/затем"


Ну и как добиться этой одновременности из потока исполнения абстрактного С++ вычислителя над программой?
1. Оно не одновременно в описании исходника;
2. Оно не одновременно в рантайме.

В то время как ваше UB требует иметь на руках неконстантную ссылку/указатель на объект (или на область памяти объекта), про который компилятор уже сделал умозаключение, что объект константный.


V>Вот эта посылка не верна. Объект снаружи и внутри — это по стандарту "один и тот же объект".

V>Его время жизни стартует внутри функции после отработки конструктора.

Для внешнего кода время жизни объекта стартует после возврата из ф-ии и вызова конструктора копирования от неконстантного prvalue.
(то, что конструктор копирования не вызывается — внешний код об этом даже не догадывается)


V>После этого он одновременно и является константным (потому что снаружи задекларирован так) и модифицируется внутри функции.


Для UB недостаточно декларации — с объектом надо что-то "делать", чтобы наблюдать "поведение", которое вы обещали "потенциально неопределённое".

До возврата из ф-ии с объектом ничего сделать нельзя.
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 10:52
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, σ, Вы писали:


σ>>>>И что «lifetime»? Он начинается внутри функции, после инициализации result.

BFE>>>Когда начинается lifetime объекта someDictionary ? Тогда, когда заканчивается конструирование объекта.
σ>>Ну. При NRVO, оно заканчивается на std::map<int, int> result;.

BFE>Нет, конечно. Даже при NRVO вычисление значения выражения buildMap() должно быть выполнено до начала инициализации someDictionary. Это следует из описания sequenced before.

BFE>А пока вычисление выражения buildMap() не закончилось, время жизни константного объекта не началось:
BFE>

BFE>The lifetime of an object of type T begins when: ... its initialization (if any) is complete

BFE>Запрет на модификацию константного объекта относится только ко времени жизни:
BFE>

BFE>Any attempt to modify a const object during its lifetime results in undefined behavior.

BFE>Ну а так, как время жизни константного объекта ещё не началось, то изменять его можно.

Но. В силу NRVO — result и someDictionary есть один и тот же объект, его лайфтайм начинается не так как ты тут описал
Re[102]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 11:01
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>Но. В силу NRVO — result и someDictionary есть один и тот же объект, его лайфтайм начинается не так как ты тут описал

Формально, нет:

In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

treat — behave toward or deal with in a certain way.
referring to — ссылаться на.

Здесь не говорится, что объект один и тот же. Здесь говорится, что с этими объектами работают, как с одним объектом опуская некоторые операции. Нигде не сказано, что пропуск операции — это тоже самое, что её отсутствие.
И каждый день — без права на ошибку...
Re[114]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:09
Оценка:
Здравствуйте, σ, Вы писали:

σ>Т.е. ты уже N кругов ищешь по слову created (ну и читаешь, что нашёл, естественно), но так и не понял разницу между an object is created и object lifetime starts?


А вы все эти N кругов занимаетесь начетничеством.

σ>>>Не прикидывайся. Появляется только объект типа const demo. Это не только здравому смыслу соответствует.


S>>Только вот фокус в том, что пока инициализация const demo d не завершилась, есть объект типа demo.


σ>Пруф?


Уже приводился в виде примеров кода и от меня, и от T4r4sB. Внутри конструктора this указывает на demo, а не на const demo.

S>>Тем, что внутри конструктора мы имеем demo. После его успешного завершения уже const demo.


σ>Пруф?


Сделайте typeid для d.

S>>Ну как-то так получается, что эмпирический опыт исходя из которого я здесь привожу примеры, основан на C++.


σ>Нет, он не основан на C++. Твой эмпирический опыт — это максимум взаимодействие с некоторыми т.н. реализациями C++.

σ>Ну и, самое главное, ты ведь приводишь не свой опыт, а вещаешь свои кривые его интерпретации.

Да я бы с удовольствием выслушал то, как оно должно быть и поучился бы. Но... Вы же не можете связно изложить что к чему и почему, да еще и примерами проиллюстрировать
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 11:13
Оценка: :)
Здравствуйте, vdimas, Вы писали:

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


V>>Нет. Никаких "сперва". Константный объект снаружи и не-константный объект внутри, в случае NRVO это "один и тот же объект" (да, звучит как коллизия, но все же, так написано в стандарте). То есть, наружный константный объект модифицируется внутри функции через неконстантное имя. Это все есть одновременно, а не "сначала/затем"


V>Ну и как добиться этой одновременности из потока исполнения абстрактного С++ вычислителя над программой?

V>1. Оно не одновременно в описании исходника;
V>2. Оно не одновременно в рантайме.

выше показывал как:
1. исходя из внешней декларации — объект является константным (по определению декларации из стандарта — тип декларируемого объекта принимается такой, который указан при декларации этого объекта. Ссылку на стандарт могу поискать, мелькала тут выше по теме вроде)
2. его время жизни началось так как внутри функции отработала его инициализация (конструктор завершил работу). Обращаю внимание, на этот момент действие пункта 1. распространяется в полной мере, объект сейчас константный
3. он используется как неконстантный — внутри функции через неконстантное имя объекту производится модификация полей. Снова обращаю внимание, на этот момент действие пункта 1. распространяется в полной мере, объект сейчас константный

Вот так и добились


V>В то время как ваше UB требует иметь на руках неконстантную ссылку/указатель на объект (или на область памяти объекта), про который компилятор уже сделал умозаключение, что объект константный.


Никаких ссылок/указателей. Доступ к объекту производится по его именам, коих два, одно снаружи функции другое внутри. Внешнее имя типизировано константно. Внутреннее — не константно.

И ни о каких областях памяти говорить не нужно, это совершенно другой аспект.


V>>Вот эта посылка не верна. Объект снаружи и внутри — это по стандарту "один и тот же объект".

V>>Его время жизни стартует внутри функции после отработки конструктора.

V>Для внешнего кода время жизни объекта стартует после возврата из ф-ии и вызова конструктора копирования от неконстантного prvalue.

V>(то, что конструктор копирования не вызывается — внешний код об этом даже не догадывается)

Время жизни объекта по стандарту стартует после отработки конструктора, то есть, после того как конструктор отработал — объект живой. А конструктор (для объекта который один и тот же — внутренний и внешний) отрабатывает внутри функции. То есть, время жизни объекта, доступного по внешнему имени (вроде в примере это было someDictionary) начинается внутри функции, после отработки конструктора для result


V>>После этого он одновременно и является константным (потому что снаружи задекларирован так) и модифицируется внутри функции.


V>Для UB недостаточно декларации — с объектом надо что-то "делать", чтобы наблюдать "поведение", которое вы обещали "потенциально неопределённое".


Для UB достаточно выполнить эти условия:

Any attempt to modify a const object during its lifetime results in undefined behavior.

И эти условия выполнены.

V>До возврата из ф-ии с объектом ничего сделать нельзя.

а это уже не важно
Re[103]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 11:14
Оценка: :)
BFE>>>А пока вычисление выражения buildMap() не закончилось, время жизни константного объекта не началось:
BFE>>>

σ>>The lifetime of an object of type T begins when: ... its initialization (if any) is complete

σ>>Ну и какая инициализация для этого объекта должа быть complete? Первая (std::map<int, int> result;) или последняя (которая для someDictionary)?
BFE>Последняя. Та, которая пропускается. Вы видимо не понимаете, что опущение (omitter) операции не отменяет момент старта времени жизни константного объекта.

Короче. (При NRVO) возможны только две вещи, если ты хочешь прицепиться к лайфтайму и инициализации
1. Если лайфтайм начинается после первой инициализации, то объект константный уже в функции и его модифицировать — UB
2. Если после последней, то объект вне lifetime на протяжении выполнения всей функции, и его модифицировать — UB

BFE>>>Запрет на модификацию константного объекта относится только ко времени жизни:

BFE>>>

σ>>Any attempt to modify a const object during its lifetime results in undefined behavior.

BFE>>>Ну а так, как время жизни константного объекта ещё не началось, то изменять его можно.
BFE>>>Нет тут никакого UB.

σ>>Раз время жизни объекта не началось, то result.insert(42, 43); — вызов метода на объекте до начала времени жизни? Тогда получается UB есть.

BFE>Разумеется это не так. Объект может изменятся внутри конструктора

И к чему ты это? По-твоему, std::map<int, int> buildMap() это конструктор?

σ>>>>Или объект сначала вроде как создаётся константным (const std::map<int, int> someDictionary), но потом становится неконстантным (std::map<int, int> result;), а опять константным не становится, и его можно менять даже после const std::map<int, int> someDictionary = buildMap();?

BFE>>>Близко нет.
σ>>Ты наверное опечатался когда хотел написать «ближе нет»?
BFE>Нет.

σ>>По крайней мере кое-то в CWG согласен, что, видимо, согласно текущему тексту стандарта, такое описание самое (формально) корректное .

σ>>В общем, я спалил ответ на свой вопрос, по крайней мере соответствующий стандарту буквально (насколько стандарт тут дефектен, это отдельный разговор), а ты даже не понял.
BFE> апелляция к авторитету

Не в тему.

BFE>Вы ошибаетесь и ваш авторитет ошибается. Я же вас с самого начала предупреждал, что попытка описания на естественном языке формального поведения однозначно приведёт к проблемам толкования.


Если я не дал релевантных ссылок, это ещё не делает его описанием на естественном языке. То, что я описал, вполне формально-буквально следует из стандарта.

BFE>И ваше описание формально не корректно. Если формально, то константный объект не может становится неконстантным: A const object is an object of type const T.


И как из этой цитаты следует, может или не может?

Интересно самому найти формальное описание? Или мне привести?
Могу пока дать поцсказку. Ты ведь, надеюсь, в курсе, чем создание объекта отличается от начала его времени жизни? Ну так вот. Ты, похоже, забыл, что создание объекта sequenced before, и сразу перескочил на описание начала времени жизни, и зря. Почитай внимательно про создание объекта

BFE>Другое дело, что есть периоды существования объекта (не путайте со временем жизни), когда константный объект можно изменять.


С этим кто-то спорил? Я на это даже ссылку давал в https://rsdn.org/forum/cpp/8585023.1
Автор: σ
Дата: 21.08.23

Только этот параграф тут ни при чём.

BFE>А то, что вы тут описываете, это неформальное описание, которое даёт тот же видимый эффект, но верным от этого не становится.


Я описываю формальное описание.
Отредактировано 22.08.2023 11:56 σ . Предыдущая версия .
Re[108]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:21
Оценка:
Здравствуйте, vopl, Вы писали:

V>Приведена выдержка из стандарта, в которой определяется что суть есть "object creation". И как после нее можно заявлять о потере смысла? Она и определяет смысл. Она есть смысл.


Или проблема в том, что все это раскидано в разных кусках стандарта. Которые нужно увязать друг с другом, чтобы получить общую картину.

V>Какой еще lifetime Приведено оригинальное определение. В нем нет ни слова про lifetime.


Или нужно просто посмотреть на чуть более расширенную цитату (https://timsong-cpp.github.io/cppwp/basic.memobj#intro.object-1):

The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]). An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).

[Note 1: A function is not an object, regardless of whether or not it occupies storage in the way that objects do. — end note]

The properties of an object are determined when the object is created. An object can have a name ([basic.pre]). An object has a storage duration ([basic.stc]) which influences its lifetime ([basic.life]). An object has a type ([basic.types]).

[Note 2: Some objects are polymorphic ([class.virtual]); the implementation generates information associated with each such object that makes it possible to determine that object's type during program execution. — end note]


Т.е. в разделе про создание объектов уже ссылаются на lifetime.
Отредактировано 22.08.2023 11:24 so5team . Предыдущая версия .
Re[102]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 11:23
Оценка:
Здравствуйте, σ, Вы писали:

σ>Ну и какая инициализация для этого объекта должа быть complete? Первая (std::map<int, int> result;) или последняя (которая для someDictionary)?


Всего тут 3 лайфтайма:
— локальной переменной внутри buildMap;
— безымянного/временного возвращённого значения;
— целевого константного, получаемого конструктором копирования.

Все три объекта живут последовательно.

А что касается оптимизаци... ))

Вот тут:
#include <iostream>

class SomeObj {
public:
    SomeObj(int i) : index{i} {}
    
    //SomeObj(SomeObj && other) = delete;

    int index;
};

SomeObj buildObj() {
    SomeObj result = 42;
    result.index = 43;
    return result;
}

int main() {
    const SomeObj obj = buildObj();
    const_cast<int&>(obj.index) = 44;
    std::cout << obj.index;
}

после оптимизации даже не создаётся объект:
main:
        sub     rsp, 8
        mov     esi, 44
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        add     rsp, 8
        ret

просто выводится 44 в cout.
А могло бы вывести 43. ))
Бо там UB в const_cast<int&>(obj.index) = 44;, а не при объявлении объекта.
Re[83]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 11:27
Оценка: +1 :)
Здравствуйте, so5team, Вы писали:

S>Какой-то здесь, право слово, фигней страдают, пытаясь найти некий гипотетический UB. Хотя с NRVO и получением константного объекта из неконстантного можно запросто наступить на несложные грабли:


Блин, недочитал до сюда, породил аналогичный пример:
http://www.rsdn.org/forum/cpp/8585549.1
Re[115]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 11:27
Оценка:
σ>>Т.е. ты уже N кругов ищешь по слову created (ну и читаешь, что нашёл, естественно), но так и не понял разницу между an object is created и object lifetime starts?

S>А вы все эти N кругов занимаетесь начетничеством.


И?

σ>>>>Не прикидывайся. Появляется только объект типа const demo. Это не только здравому смыслу соответствует.


S>>>Только вот фокус в том, что пока инициализация const demo d не завершилась, есть объект типа demo.


σ>>Пруф?


S>Уже приводился в виде примеров кода и от меня, и от T4r4sB. Внутри конструктора this указывает на demo, а не на const demo.


Пример кода это не пруф.

S>>>Тем, что внутри конструктора мы имеем demo. После его успешного завершения уже const demo.


σ>>Пруф?


S>Сделайте typeid для d.


Это, по-твоему, пруф?

S>>>Ну как-то так получается, что эмпирический опыт исходя из которого я здесь привожу примеры, основан на C++.


σ>>Нет, он не основан на C++. Твой эмпирический опыт — это максимум взаимодействие с некоторыми т.н. реализациями C++.

σ>>Ну и, самое главное, ты ведь приводишь не свой опыт, а вещаешь свои кривые его интерпретации.

S>Да я бы с удовольствием выслушал то, как оно должно быть и поучился бы. Но... Вы же не можете связно изложить что к чему и почему


Тащем-та могу. Хочу на попытки других посмотреть.
Re[84]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:34
Оценка: +1
Здравствуйте, vdimas, Вы писали:

S>>Какой-то здесь, право слово, фигней страдают, пытаясь найти некий гипотетический UB. Хотя с NRVO и получением константного объекта из неконстантного можно запросто наступить на несложные грабли:


V>Блин, недочитал до сюда, породил аналогичный пример:

V>http://www.rsdn.org/forum/cpp/8585549.1

Ага. При этом я был сильно удивлен тому, насколько похожими они получились, а ведь мы не сговаривались
Re[116]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:37
Оценка:
Здравствуйте, σ, Вы писали:

S>>А вы все эти N кругов занимаетесь начетничеством.


σ>И?


И это не есть хорошо.

σ>Пример кода это не пруф.


Ну, некоторые думают, что практика -- это критерий проверки теории. Ошибаются, наверное.

S>>Сделайте typeid для d.


σ>Это, по-твоему, пруф?


Да.

S>>Да я бы с удовольствием выслушал то, как оно должно быть и поучился бы. Но... Вы же не можете связно изложить что к чему и почему


σ>Тащем-та могу. Хочу на попытки других посмотреть.


Не вопрос, я подожду. Учиться никогда не поздно.
Re[117]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 11:42
Оценка:
σ>>Пример кода это не пруф.

S>Ну, некоторые думают, что практика -- это критерий проверки теории.


Да пожалуйста. Только сначала теоретически опиши, чтобы было чего проверять
От одного тут попросил описать ожидаемое поведение — в ответ только пикрил
Отредактировано 22.08.2023 11:47 σ . Предыдущая версия .
Re[103]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 11:45
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


V>>Но. В силу NRVO — result и someDictionary есть один и тот же объект, его лайфтайм начинается не так как ты тут описал

BFE>Формально, нет:
BFE>

BFE>In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

BFE>treat — behave toward or deal with in a certain way.
BFE>referring to — ссылаться на.

BFE>Здесь не говорится, что объект один и тот же. Здесь говорится, что с этими объектами работают, как с одним объектом опуская некоторые операции. Нигде не сказано, что пропуск операции — это тоже самое, что её отсутствие.


Вот это поворот .. Какая разница, "он один и тот же" или "действия с ними трактуются как с одним и тем же". Если "действия с ними трактуются как с одним" — то логика такая:

внешнее и внутреннее имена трактуются как если они ссылаются на один и тот же объект. Тогда время жизни объекта, означенного внешнем именем — трактуется как время жизни как будто бы "того же объекта". То есть, не важно как мы эту штуку назовем — один и тот же объект, или "нечто трактуемое как один и тот же объект" — все эффекты около этой штуки будут одинаковыми в обоих случаях. Более того, эти два подхода не различимы, не возможно определить, имеем мы дело с "одним и тем же объектом" или с чемто, "с чем работать нужно как с одним и тем же"
Re[118]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:49
Оценка:
Здравствуйте, σ, Вы писали:

σ>Да пожалуйста. Только сначала теоретически опиши, чтобы было чего проверять


Так у нас вы тут за теоретика. Вот, доказываете, что если есть const demo d, то в конструкторе d мы будем иметь дело с const demo. А на практике так не получается.

Пока как-то так.
Re[119]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 11:53
Оценка:
σ>>Да пожалуйста. Только сначала теоретически опиши, чтобы было чего проверять

S>Так у нас вы тут за теоретика. Вот, доказываете, что если есть const demo d, то в конструкторе d мы будем иметь дело с const demo. А на практике так не получается.


Как можно сказать, равно ли A B, если из них ты знаешь только A или только B
Если ты не знаешь теории, как ты определяешь, получается на практике в соответствие с теорией или нет
Re[120]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 11:57
Оценка:
Здравствуйте, σ, Вы писали:

S>>Так у нас вы тут за теоретика. Вот, доказываете, что если есть const demo d, то в конструкторе d мы будем иметь дело с const demo. А на практике так не получается.


σ>Как можно сказать, равно ли A B, если из них ты знаешь только A или только B


Я правильно понимаю, что вы можете привести пример, который докажет, что в конструкторе const demo тип именно const demo, а не demo?
Re[109]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 12:03
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>Приведена выдержка из стандарта, в которой определяется что суть есть "object creation". И как после нее можно заявлять о потере смысла? Она и определяет смысл. Она есть смысл.


S>Или проблема в том, что все это раскидано в разных кусках стандарта. Которые нужно увязать друг с другом, чтобы получить общую картину.


V>>Какой еще lifetime Приведено оригинальное определение. В нем нет ни слова про lifetime.


S>Или нужно просто посмотреть на чуть более расширенную цитату (https://timsong-cpp.github.io/cppwp/basic.memobj#intro.object-1):

S>

The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is created by a definition, by a new-expression ([expr.new]), by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created ([conv.rval], [class.temporary]). An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).

S>[Note 1: A function is not an object, regardless of whether or not it occupies storage in the way that objects do. — end note]

S>The properties of an object are determined when the object is created. An object can have a name ([basic.pre]). An object has a storage duration ([basic.stc]) which influences its lifetime ([basic.life]). An object has a type ([basic.types]).

S>[Note 2: Some objects are polymorphic ([class.virtual]); the implementation generates information associated with each such object that makes it possible to determine that object's type during program execution. — end note]


S>Т.е. в разделе про создание объектов уже ссылаются на lifetime.


Cсылаются на lifetime не в разделе про создание объектов. Cсылаются на lifetime в разделе Object model. В этом разделе говорится,
что делается с объектами в программе
что такое создание объекта (вот это есть определение создания объекта. И тут lifetime-а нет)
как объект связан со storage и какие этапы там с ним происходят (а вот тут уже есть lifetime. Но это не про создание объекта, это его другой аспект)

далее чуть подробнее раскрывается, что свойства объекта определяюстся в момент создания.
и lifetime это лишь одно из свойств объекта

Обрати внимание, это раздел не "про создание объекта", это раздел "про объект в целом", называется "Object model", в нем кроме аспекта "создания" есть еще много всего другого, в частности, lifetime

Мир Дружба Жвачка
Re[110]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 12:13
Оценка:
Здравствуйте, vopl, Вы писали:

V>что такое создание объекта (вот это есть определение создания объекта. И тут lifetime-а нет)


Не могу согласиться с тем, что фраза, перечисляющая способы создания объектов (by definition, by new-expression и т.д.), есть определение такого понятия как "создание объекта". Тем более, что создание объекта в качестве временного объекта и посредством new-expression -- это разный набор действий (т.е. создание объекта в каждом из способов будет означать несколько разный набор операций).

Т.е. эта фраза перечисляет легальные способы возникновения объектов в программе. Типа если объект появился в результате одного действия из перечисленных, то он считается созданным.

Собственно, как раз то, что раньше объекты могли возникать в программе нелегально с точки зрения стандарта, и пришлось вводить такие вещи, как implicit lifetime types, implicitly creates в купе с std::start_lifetime_as и т.д.

Опять же это все к тому, что стандарт написан специальным языком для специалистов и для специфических целей.
Re[106]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 12:19
Оценка:
Здравствуйте, vopl, Вы писали:

V>глобальность непричем, вот такой кейс имеет то же самое "гипотетическое UB"

V>
V>struct T {int m;};

V>T make()
V>{
V>    T inner;
V>    inner.m = 220;
V>    return inner;
V>}

V>int main()
V>{
V>    const T outer = make();

V>    return 0;
V>}


В этом случае не получится ни объяснить это UB, ни продемонстрировать потенциальный кейз, где UB может себя проявить.
Оно возможно только в фазе неоконченной инициализации модуля, но на такое UB можно попасть и при простом статическом const int i = calcValue();


V>>Для локальных констант оно невоспроизводимо, т.к. доступ к константе происходит только после инициализации переменной.

V>не важно когда происходит доступ.

Важно, согласно определению lifetime, да и просто здравого смысла.


V>Тип объекта, определяемый декларацией потенциально является константным.


Но что-то выполнить в коде и пронаблюдать потенциальное неопределённое поведение можно только после объявления константы, где объявление локальной константы по стандарту совмещено с определением.
Этот момент и не даёт продемонстрировать неопределённость на практике.

Исключение составляет extern const, но это опять заход на новый круг про глобальные переменные. ))


V>На этой основе компилятор может делать всякие предположения относительно доступа к этому объекту. И объект после своего создания/инициализации используется как мутабельный.


В твоём примере объект outer считается не созданным до возврата из make.


V>вот так оно может быть развернуто компилятором

V>

V>struct T {int m;};

V>int main()
V>{
V>    count T outer{};// только конструктор будет от неконстантного имени. Да я знаю что конструктору плевать, просто отмечаю сей факт

V>    T& inner = const_cast<T&>(outer);
V>    inner.m = 220;

V>    return 0;
V>}


Не может и не будет. ))

Там будет другое:
— sub RSP на необходимую величину для размещения всех локальных переменных;
— присвоить регистру EDI адрес outer (допустим, значение RSP+16);
— call make с параметром в регистре EDI;
— считать outer инициализированным.

А если указать флаг оптимизации, то будет простое использование константы 220, безо-всяких переменных, объектов и ф-ий.


V>наверное да.. Я игнорирую тезисы которые просто высказываются в утвердительной форме, без обоснований


Основание можно спросить, т.к. вам тут многое говорится как "и так известное", и окружающие ХЗ что именно непонятно.


V>>Что характерно, в статической фазе константе const int i будет присвоено значение 0, а в динамической фазе эта константа будет перезаписана результатом вызова calValue(). Не смущает, ы? ))

V>это все не важно

Было бы не важно, но вы пока мест показали именно такое UB, для демонстрации которого не требовался ни RVO/NRVO, ни даже нетривиальные типы данных.
Достаточно было простого const int i = calcValue();, и сей UB живёт с самых первых версий С++ 80-х годов.
И будет жить вечно, походу. ))

И такие вещи упоминаются как сами собой разумеющиеся, т.е. не требующие обоснования, бо относятся к минимальному бэкгрраунду для С++.


V>>Так вот, услышьте уже, что доступ к неинициализированным данным модуля является UB и безо-всякого RVO/NRVO, т.е. это другое UB, нерелевантное обсуждаемому.

V>Услышал. Сабжевое "гипотетическое UB" — не про доступ к неинициализированным данным.

Но показать не можете. ))
Пока что была "демонстрация" только для глобальный переменной.

А для локальной ты никак не перепрыгнешь обязательность инициализации константы при объявлении.


V>В кейсе с "гипотетическим UB" все инициализировано до использования.


До использования константной переменной.
Ты всерьёз думаешь, что никто не понял ваш аргумент про "фактическое слияние" одного объекта с другим?

Любая фактическая подмена, которая не нарушает семантику, является "не важной" для рассуждений, до тех пор, пока язык даёт свои гарантии.
А он их даёт, т.к. переменная outer может быть использована только после того, как переменная inner закончила свой жизненный цикл.

А тот факт, что обе переменные обозначали одну и ту же область памяти — это и есть суть RVO оптимизации (не обязательно, кстате, было заострять на более узком кейзе NRVO, бо оно попахивало очередным непониманием материала).


V>Это был пример в котором объявлен константный объект, он создан/инициализирован


Не создан и не инициализирован.
Более того, мог быть создан объект совсем другого типа!

Простой пример:
#include <iostream>

struct Base {
    int value;
    char filler[256];
};

Base make() {
    Base result;
    result.value = 42;
    return result;
}

struct Derived : Base {
    Derived(const Base & other) {
        value = other.value;
    }
};

struct SomeObj {
    int value;

    SomeObj(const Base & other) {
        value = other.value;
    }
};

int main() {
    const Base outer1 = make();
    std::cout << outer1.value;

    const Derived outer2 = make();
    std::cout << outer2.value;

    const SomeObj outer3 = make();
    std::cout << outer3.value;

    return 0;
}


Для всех 3-х объектов будет идентичный код в случае инлайна конструтора копирования от Base.


V>и потом с ним идет работа как не с константным, что есть UB.


Наоборот, сначала идёт работа как с неконстантным, а потом этот объект становится доступным для операций на вызывающей стороне, приобретая константность.
У тебя нет возможность использовать переменную outer до возврата из make.


V>>Но после динамической фазы инициализации модуля, либо же, в этой фазе, но с учётом гарантированной последовательности инициализации глобальных переменных модуля, можно избежать упомянутого мною UB, и RVO/NRVO опять на него никак не влияют. Всё.

V>Не в ту сторону все.

А ничего другого, показывающего некий UB, вы так и не показали.


V>Пример посмотрел, понял, там отписал. В нем другой способ инициирования записи в константный объект, в общем, этот пример не принимается как полный, но очень хорошо показывает запись в константный объект, которая есть и в кейсе с "гипотетическим UB"


Вообще-то, тот пример намекал на возможность подобной утечки и через buildMap(), если адрес локальной переменной result куда-то протечёт как неконстантный.

Но! Утекание адреса локальной переменной является UB еще до рассждений об RVO, такое утекание — грубейшая ошибка!
Не везёт вам... ))

Итого, мы упомянули уже три известных UB:

1. UB с доступом к неинициализированному значению при инициализации глобальных переменных.
Решение: обращаться к глобальным переменным модуля в фазе динамической инициализации необходимо согласно гарантированному порядку их инициализации.
К переменным из других модулей можно обращаться только по окончании фазы динамической инициализации (т.е. после вызова main)

2. UB с константностью при наличии побочных эффектов в конструкторах.
Решение:
— такие объекты не стоит делать константами;
— такие объекты не стоит делать перемещаемыми/копируемыми.

3. UB при утекании адресов/ссылок на локальные переменные.
Решение: не давать им утекать, это грубая ошибка.

Но не видели еще работающего примера с демонстрацией UB вокруг константности, вызванного исключительно RVO!
Т.е. когда о любых других UB речи не идёт.

Итак, пример будет?
(желательно с объяснением, конечно, бо упомянутые 3 UB объяснить проще простого)
Отредактировано 23.08.2023 11:56 vdimas . Предыдущая версия . Еще …
Отредактировано 22.08.2023 12:23 vdimas . Предыдущая версия .
Отредактировано 22.08.2023 12:21 vdimas . Предыдущая версия .
Re[106]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 22.08.23 12:31
Оценка:
Здравствуйте, vopl, Вы писали:

V>Да штош такое то) Сабжевый наш UB — НЕ имеет природу недоинициализированных глобальных переменных в динамической фазе инициализации.


Пока что был только такой работающий пример от σ, и только этот пример можно было предметно пороть.

Твои вариации с локальным константным объектом никакого потенциального UB не несут, обсуждать нечего.


V>Он про запист в гипотетически константный, нормально проинициализированный объект.


Ну так доступ к этому константному объекту уже есть или еще нет? ))

Как ты можешь продемонстрировать "неопределённое поведение" константного объекта в отсутствии доступа к целевому константному объекту?
Нет поведения — нет неопределённости.
Re[121]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 12:53
Оценка: -1
S>>>Так у нас вы тут за теоретика. Вот, доказываете, что если есть const demo d, то в конструкторе d мы будем иметь дело с const demo. А на практике так не получается.

σ>>Как можно сказать, равно ли A B, если из них ты знаешь только A или только B


S>Я правильно понимаю, что вы можете привести пример, который докажет, что в конструкторе const demo тип именно const demo, а не demo?


Доказывают, приводя доказательство

Но вообще ладно, вот: пример "2+2=4" доказывает, что в конструкторе const demo тип именно const demo.
Отредактировано 22.08.2023 12:55 σ . Предыдущая версия .
Re[111]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 12:53
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>что такое создание объекта (вот это есть определение создания объекта. И тут lifetime-а нет)


S>Не могу согласиться с тем, что фраза, перечисляющая способы создания объектов (by definition, by new-expression и т.д.), есть определение такого понятия как "создание объекта".


но это так

S>Тем более, что создание объекта в качестве временного объекта и посредством new-expression -- это разный набор действий (т.е. создание объекта в каждом из способов будет означать несколько разный набор операций).

вот тут наверное немного недопонимание есть: надо различать создание, конструирование, лайфтайм и т.д. Созданный объект не факт что можно использовать как обычно, он может быть еще непроинициализирован, его лайфтайм может еще не начаться. Другими словами: объекта в качестве временного объекта или объект, порожденный new-expression — они претерпевают не только "создание". Там масса всего интересного происходит
— выделяется соответствующий storage
— создается объект
— инициализируется
— стартует его lifetime

и только после всей этой пачки объект отдается на вызывающий уровень. Обрати внимание, тут "создание" — это один из шагов. И он не объемлет остальные, но стоит с ними на одном уровне. Фактически, "создание объекта" — это просто условность, некая реперная точка, после которой объект обретает свои свойства (имя, тип и прочие). Вот такую реперную точку называют "созданием объекта". Такая реперная точка "создание", как один из шагов проводится при определении объекта, в new-expression, а так же, просто как некая неявная штука — называется implicit creating. То есть, implicit creation — это такой creаting, только "неявный". Например, std::memcpy — делает такой implicit creating, а следовательно, после std::memcpy у объекта появляются имя, тип и прочее, далее его можно тем или иным способом проинициализировать, стартануть liifetime, далее с ним можно делать регулярную работу...

S>Т.е. эта фраза перечисляет легальные способы возникновения объектов в программе. Типа если объект появился в результате одного действия из перечисленных, то он считается созданным.


ну да

S>Собственно, как раз то, что раньше объекты могли возникать в программе нелегально с точки зрения стандарта, и пришлось вводить такие вещи, как implicit lifetime types, implicitly creates в купе с std::start_lifetime_as и т.д.


ага

S>Опять же это все к тому, что стандарт написан специальным языком для специалистов и для специфических целей.


ну вот мы с тобой сейчас читаем понемножку (ты же читаешь, да? Ведь не веришь же мне на слово?) и все становится понятно. Значит мы с тобой специалисты И у нас специальный цели
Re[104]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 12:55
Оценка:
Здравствуйте, σ, Вы писали:

σ>Короче. (При NRVO) возможны только две вещи, если ты хочешь прицепиться к лайфтайму и инициализации

σ>1. Если лайфтайм начинается после первой инициализации, то объект константный уже в функции и его модифицировать — UB
σ>2. Если после последней, то объект вне lifetime на протяжении выполнения всей функции, и его модифицировать — UB
Это ложная альтернатива. Вот цитата:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
object, even if the constructor selected for the copy/move operation and/or the destructor for the object
have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
operation as simply two different ways of referring to the same object.

Тут говорится, что реализация работает двумя различными путями с двумя объектами как с одним и тем же объектом. Здесь не утверждается, что объект один. Объектов два: "source and target". А работают с ними, как с одним и тем же объектом опуская операции копирования и перемещения. То, что эти операции опускаются, не означает, что объект один — формально объектов два, но работают с ними, как с одним объектом. Из того, что операцию копирования пропустили не следует, что начало времени жизни объекта куда-то перенеслось. Начало время жизни объекта осталось там же, где и было. И это относится к обоим объектам.

std::map<int, int> buildMap()
{
    std::map<int, int> result; // создали неконстантный объект result, после выполнения конструктора началось время жизни объекта result
    result.insert(42, 43);     // изменили неконстантный объект result
    return result;             // скопировали неконстантный объект result в возвращаемый неконстантный объект (*) - это операция пропускается
                               //   после завершения конструктора временного объекта началось время жизни возвращаемого неконстантного объекта несмотря на то, что операция копирования была пропущена.
                               // перед вызовом деструктора объекта result заканчивается время жизни объекта result
                               // разрушили неконстантный объект result (*) - это операция пропускается
}

const std::map<int, int> someDictionary = buildMap(); // возвращаемый функцией buildMap() неконстантный объект передаётся в конструктор класса map             (*) - это операция пропускается 
                                                      // внутри конструктора возвращаемый функцией buildMap() неконстантный объект перемещается (копируется)   (*) - это операция пропускается
                                                      // после завершения выполнения конструктора                                                              (*) - это операция пропускается 
                                                      //   началось время жизни константного объекта обозначаемого переменной someDictionary 
                                                      // время жизни возвращаемого функцией buildMap() неконстантного объекта окончено  
                                                      // после выполнения выражения возвращаемый функцией buildMap() неконстантный объект разрушается          (*) - это операция пропускается

— вот так (без подробностей) может выглядеть выполнение на абстрактной машине. Как видите время жизни константного объекта обозначаемого переменной someDictionary начинается после создания и модификации объекта.


σ>>>Раз время жизни объекта не началось, то result.insert(42, 43); — вызов метода на объекте до начала времени жизни? Тогда получается UB есть.

BFE>>Разумеется это не так. Объект может изменятся внутри конструктора
σ>И к чему ты это?
К тому, что методы можно вызывать до начала времени жизни.

σ> По-твоему, std::map<int, int> buildMap() это конструктор?

нет.

BFE>>Вы ошибаетесь и ваш авторитет ошибается. Я же вас с самого начала предупреждал, что попытка описания на естественном языке формального поведения однозначно приведёт к проблемам толкования.

σ>Если я не дал релевантных ссылок, это ещё не делает его описанием на естественном языке.
Ссылки на неформальный язык не делают описание формальным.

σ> То, что я описал, вполне формально-буквально следует из стандарта.

Формально-буквально из стандарта вообще мало чего следует.

BFE>>И ваше описание формально не корректно. Если формально, то константный объект не может становится неконстантным: A const object is an object of type const T.

σ>И как из этой цитаты следует, может или не может?
Неконстантный объект не будет удовлетворять определению константного объекта.

σ>Интересно самому найти формальное описание? Или мне привести?

σ>Могу пока дать поцсказку. Ты ведь, надеюсь, в курсе, чем создание объекта отличается от начала его времени жизни? Ну так вот. Ты, похоже, сразу перескочил на описание начала времени жизни, и зря. Почитай внимательно про создание объекта
Приведите, но имейте ввиду, что до начала жизни константный объект можно менять. Надеюсь вам понятно, что, например, во время выполнения конструктора константный объект остаётся константным объектом несмотря на то, что изменяется?

σ>Я описываю формальное описание.

Формальное описание может быть только на формальном языке.
И каждый день — без права на ошибку...
Re[107]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 12:58
Оценка:
Здравствуйте, vdimas, Вы писали:

сдаюсь, ты победил
Re[112]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 22.08.23 13:04
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>вот тут наверное немного недопонимание есть: надо различать создание, конструирование, лайфтайм и т.д. Созданный объект не факт что можно использовать как обычно, он может быть еще непроинициализирован, его лайфтайм может еще не начаться. Другими словами: объекта в качестве временного объекта или объект, порожденный new-expression — они претерпевают не только "создание". Там масса всего интересного происходит

V>- выделяется соответствующий storage
V>- создается объект
V>- инициализируется
V>- стартует его lifetime

Здесь понятно все, кроме "создается объект".
Как по мне, так создание -- это как раз выделение хранилища и, если возможно, инициализация. После того, как объект создан, его lifetime считается начатым. Хотя с lifetime, емнип, не все так просто, т.е. lifetime может начаться, но не считаться полностью начатым.

V>ну вот мы с тобой сейчас читаем понемножку (ты же читаешь, да? Ведь не веришь же мне на слово?)


Отдельные фрагменты.

V>и все становится понятно.


Не сказал бы.

Но вообще печально, что такими вещами приходится заниматься. Да не буду лишний раз повторять банальности.

V>И у нас специальный цели


Или так: нет цели, но есть путь

Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 13:08
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, σ, Вы писали:


σ>>Короче. (При NRVO) возможны только две вещи, если ты хочешь прицепиться к лайфтайму и инициализации

σ>>1. Если лайфтайм начинается после первой инициализации, то объект константный уже в функции и его модифицировать — UB
σ>>2. Если после последней, то объект вне lifetime на протяжении выполнения всей функции, и его модифицировать — UB
BFE>Это ложная альтернатива. Вот цитата:
BFE>

BFE>When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
BFE>object, even if the constructor selected for the copy/move operation and/or the destructor for the object
BFE>have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
BFE>operation as simply two different ways of referring to the same object.

BFE>Тут говорится, что реализация работает двумя различными путями с двумя объектами как с одним и тем же объектом. Здесь не утверждается, что объект один. Объектов два: "source and target".

source and target это не объекты, это "two different ways of referring to the same object"
Re[113]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 13:16
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, vopl, Вы писали:


V>>вот тут наверное немного недопонимание есть: надо различать создание, конструирование, лайфтайм и т.д. Созданный объект не факт что можно использовать как обычно, он может быть еще непроинициализирован, его лайфтайм может еще не начаться. Другими словами: объекта в качестве временного объекта или объект, порожденный new-expression — они претерпевают не только "создание". Там масса всего интересного происходит

V>>- выделяется соответствующий storage
V>>- создается объект
V>>- инициализируется
V>>- стартует его lifetime

S>Здесь понятно все, кроме "создается объект".

S>Как по мне, так создание -- это как раз выделение хранилища и, если возможно, инициализация.

нене, выделение хрнилища, инициализация и прочее — это не создание. Создание это просто такая точка, в которой объект формально обретает свои свойства (имя, тип, storage duration ...)

S>После того, как объект создан, его lifetime считается начатым. Хотя с lifetime, емнип, не все так просто, т.е. lifetime может начаться, но не считаться полностью начатым.

после того, как объект создан — ему можно сделать инициализацию/конструирование, после окончания которых начнется его lifetime. А можно и не сделать, тогда у нас будет объект вне lifetime и его нельзя использовать обычными способами. А может это будет спец-объект с implicit lifetime, тогда он после создания сразу может быть использован обычным способом.
Re[104]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 13:18
Оценка: +1
Здравствуйте, vopl, Вы писали:

BFE>>Здесь не говорится, что объект один и тот же. Здесь говорится, что с этими объектами работают, как с одним объектом опуская некоторые операции. Нигде не сказано, что пропуск операции — это тоже самое, что её отсутствие.


V>Вот это поворот .. Какая разница, "он один и тот же" или "действия с ними трактуются как с одним и тем же".

Формально разница есть. UB привязано ко времени жизни. Время жизни привязано к концу/началу выполнения конструктора/деструктора. Конц/начало выполнения конструктора/деструктора привязано к последовательностям выполнения выражений. Если выполнение выражения пропускается, то вот "точки привязки" времени жизни остаются. Поэтому ссылаемся мы на один и тот же объект, но делаем вид, что это разные объекты. Делаем вид — это рассматриваем выражения так, как если бы это были разные объекты.
И каждый день — без права на ошибку...
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 13:40
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>...но делаем вид, что это разные объекты. Делаем вид — это рассматриваем...


так нельзя, все эти "делаем вид" должны иметь обоснование, а его нет. Поэтому нет никаких "делаем вид". Выдавлен copy — значит его эффект стал пустым. Весь эффект целиком. Нет оснований полагать, что copy elision относится только к части copy. Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime
Re[106]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 13:41
Оценка:
Здравствуйте, vopl, Вы писали:

BFE>>

BFE>>When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
BFE>>object, even if the constructor selected for the copy/move operation and/or the destructor for the object
BFE>>have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
BFE>>operation as simply two different ways of referring to the same object.

BFE>>Тут говорится, что реализация работает двумя различными путями с двумя объектами как с одним и тем же объектом. Здесь не утверждается, что объект один. Объектов два: "source and target".

V>source and target это не объекты, это "two different ways of referring to the same object"

А я уже писал выше по ветке: "Последнее время ссылаться на стандарт становится дурным тоном, так как комитет занят безумной попыткой описать формальное поведение на естественном английском языке. Эта задача не выполнима, так как под каждое словесное описание придётся дополнительно писать толкование написанных слов."
Ваша трактовка — иллюстрация моих слов.

Мой перевод такой:
В этих случаях реализация рассматривает источник и цель пропущенных операций копирования/перемещения как просто два разных способа сослаться на один и тот же объект.
Согласен, в общем случае можно подумать, что источник и цель — не объекты, если не учитывать контекст предыдущего предложения.
И каждый день — без права на ошибку...
Re[106]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 13:43
Оценка:
Здравствуйте, vopl, Вы писали:

V> Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime


Ну попробуйте это обосновать.
И каждый день — без права на ошибку...
Re[107]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 13:55
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


V>> Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime


BFE> Ну попробуйте это обосновать.


Ну, обоснование у меня вряд ли получится сформулировать. Вместо обоснования — приведу свою логику рассуждений:
нет оснований полагать что в стандарте под выдавливанием copy пониматся не copy а некий "copy part", так как там не указано, какие именно аспекты copy будут выдавлены а какие — нет. Таким образом я считаю что имеется ввиду весь copy целиком.

Возможно, моя логика ошибочна, но пока что я придерживаюсь именно ее.
Отредактировано 22.08.2023 13:57 vopl . Предыдущая версия .
Re[105]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 14:27
Оценка:
σ>>Короче. (При NRVO) возможны только две вещи, если ты хочешь прицепиться к лайфтайму и инициализации
σ>>1. Если лайфтайм начинается после первой инициализации, то объект константный уже в функции и его модифицировать — UB
σ>>2. Если после последней, то объект вне lifetime на протяжении выполнения всей функции, и его модифицировать — UB
BFE>Это ложная альтернатива. Вот цитата:
BFE>

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
object, even if the constructor selected for the copy/move operation and/or the destructor for the object
have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
operation as simply two different ways of referring to the same object.

BFE>Тут говорится, что реализация работает двумя различными путями с двумя объектами как с одним и тем же объектом. Здесь не утверждается, что объект один. Объектов два: "source and target".

С чего ты решил, что source and target это объекты, а не (glvalue-)выражения или переменные?
Дальше про source и target написано, что это «ways of referring to the same object».
Что, скорее, является way of referring to an object: переменная/выражение или объект? Переменную или выражение вполне можно обозвать "способом ссылаться на объект". А называть объект "способом ссылаться на объект"? Ну ХЗ…

BFE> То, что эти операции опускаются, не означает, что объект один — формально объектов два


Формально объект один, формально по-прежнему два способа на него ссылаться. Которые теперь ссылаются на один и тот же объект.

BFE>
std::map<int, int> buildMap()
{
    std::map<int, int> result; // создали неконстантный объект result, после выполнения конструктора началось время жизни объекта result
    result.insert(42, 43);     // изменили неконстантный объект result
    return result;             // скопировали неконстантный объект result в возвращаемый неконстантный объект (*) - это операция пропускается
                               //   после завершения конструктора временного объекта началось время жизни возвращаемого неконстантного объекта несмотря на то, что операция копирования была пропущена.
                               // перед вызовом деструктора объекта result заканчивается время жизни объекта result
                               // разрушили неконстантный объект result (*) - это операция пропускается
}
const std::map<int, int> someDictionary = buildMap(); // возвращаемый функцией buildMap() неконстантный объект передаётся в конструктор класса map             (*) - это операция пропускается 
                                                      // внутри конструктора возвращаемый функцией buildMap() неконстантный объект перемещается (копируется)   (*) - это операция пропускается
                                                      // после завершения выполнения конструктора                                                              (*) - это операция пропускается 
                                                      //   началось время жизни константного объекта обозначаемого переменной someDictionary 
                                                      // время жизни возвращаемого функцией buildMap() неконстантного объекта окончено  
                                                      // после выполнения выражения возвращаемый функцией buildMap() неконстантный объект разрушается          (*) - это операция пропускается

BFE>- вот так (без подробностей) может выглядеть выполнение на абстрактной машине. Как видите время жизни константного объекта обозначаемого переменной someDictionary начинается после создания и модификации объекта.

Ну ок, теперь я. Буду идти по sequenced before control flow-а. (Подразумевается C++17+, так что временных объектов нет в принципе, а не потому что copy elision)

Встречаем definition const std::map<int, int> someDictionary ….
Стандарт говорит в [intro.object]/1 «An object is created by a definition» и «The properties of an object are determined when the object is created», а в [basic.type.qualifier]/1 «The type of an object includes the cv-qualifiers specified in the decl-specifier-seq… when the object is created».
decl-specifier-seq здесь это const std::map<int, int>, так что тип объекта const std::map<int, int> (ну, по крайней мере, тип точно включает в себя const, согласно цитате).

Дальше вызывается функция buildMap, где встречаем ещё один definition: std::map<int, int> result. Как описано выше, создаётся объект и назначаются его свойства, в частности, тип std::map<int, int>.
Когда у нас NRVO, мы второй раз определяем ему свойства одного и того же объекта, убрая const-квалификатор.

Дальше надо решать, после которой инициализации мы начинаем лайфтайм. Допустим, после первой (закончившейся), для result.

Ну а дальше объект так и остаётся с типом без const-квалификатора, т.к. его properties больше не determine ¯\_(ツ)_/¯

σ>>>>Раз время жизни объекта не началось, то result.insert(42, 43); — вызов метода на объекте до начала времени жизни? Тогда получается UB есть.

BFE>>>Разумеется это не так. Объект может изменятся внутри конструктора
σ>>И к чему ты это?
BFE>К тому, что методы можно вызывать до начала времени жизни.
During construction/destruction, так что, к чему это здесь?

σ>> По-твоему, std::map<int, int> buildMap() это конструктор?

BFE>нет.
Тогда, опять же, непонятно, зачем инфа про то, что можно до начала лайфтайма вызывать.

σ>> То, что я описал, вполне формально-буквально следует из стандарта.

BFE>Формально-буквально из стандарта вообще мало чего следует.
Конкретно в данном случае можно наскрести вполне однозначных формулировок.

BFE>>>И ваше описание формально не корректно. Если формально, то константный объект не может становится неконстантным: A const object is an object of type const T.

σ>>И как из этой цитаты следует, может или не может?
BFE>Неконстантный объект не будет удовлетворять определению константного объекта.
Ну у нас после std::map<int, int> result и получается неконстантный объект. Который таким и остаётся, даже если на него ссылаться через someDictionary, после возврата из buildMap
Отредактировано 22.08.2023 14:37 σ . Предыдущая версия .
Re[100]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 15:01
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


V>Выше приводил конкретные 5 пунктов, даже с косвенной отсылкой на стандарт, посредством которых мною допускается гипотеза сабжевого UB. То есть, те 5 пунктов объясняют, каким образом допускается гипотеза про UB. Я не просил никаких ссылок на стандарт, наоборот, готов предоставить их явно для обоснования тех или иных своих тезисов. На счет того что "мне кажется" — тут да, мне действительно кажется что здесь может быть оттрактовано UB, и приведенные выше 5 пунктов объясняют каким именно образом.


Смотри, какая штука получается, давай еще раз посмотрим на этот абзац в стандарте:

https://timsong-cpp.github.io/cppwp/class.copy.elision#1

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object. If the first parameter of the selected constructor is an rvalue reference to the object's type, the destruction of that object occurs when the target would have been destroyed; otherwise, the destruction occurs at the later of the times when the two objects would have been destroyed without the optimization.


Object-то the same, но вот ways are different и это ключевой момент, который покрывает сразу и разницу времен жизни, и разницу в константности. А еще хочу заострить внимание на вот этой фразе: "an implementation is allowed...". То есть, не говорится, что компилятор обязан так сделать — ему это разрешается. И как именно он поступит, так или эдак, программист даже знать не обязан. В итоге программист имеет полное право считать, что в данном случае создаются два (или даже три) объекта, с разными временами жизни и разной константностью. И правильно тут рядом сказали: NRVO — это разновидность оптимизации, как ни крути.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 15:02 rg45 . Предыдущая версия .
Re[108]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 15:20
Оценка: :)
Здравствуйте, vopl, Вы писали:

V>>> Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime

BFE>> Ну попробуйте это обосновать.
V>Ну, обоснование у меня вряд ли получится сформулировать. Вместо обоснования — приведу свою логику рассуждений:
V>нет оснований полагать что в стандарте под выдавливанием copy пониматся не copy а некий "copy part", так как там не указано, какие именно аспекты copy будут выдавлены а какие — нет. Таким образом я считаю что имеется ввиду весь copy целиком.

lifetime — это не результат создания объекта. lifetime — это свойство объекта, присущее объекту в некоторые отрезки выполнения программы (от конца конструктора до начала деструктора).
Если это свойство выкидывается вместе с конструктором, то в коде примера ниже someDictionary вообще не начинает жить, а следовательно, const должен игнорироваться полностью, следовательно объект someDictionary можно менять (ведь его время жизни ещё не началось):
std::map<int, int> buildMap()
{
    std::map<int, int> result;
    return result;            
}

const std::map<int, int> someDictionary = buildMap();
someDictionary[42] = 43;


А это некоторый абсурд, так что выкидывать lifetime вместе с конструктором нельзя.
И каждый день — без права на ошибку...
Re[109]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 15:22
Оценка: :)
BFE>Если это свойство выкидывается вместе с конструктором, то в коде примера ниже someDictionary вообще не начинает жить, а следовательно, const должен игнорироваться полностью, следовательно объект someDictionary можно менять (ведь его время жизни ещё не началось)


https://timsong-cpp.github.io/cppwp/n4868/basic.life#7.sentence-4
https://timsong-cpp.github.io/cppwp/n4868/res.on.objects#2
Отредактировано 22.08.2023 15:26 σ . Предыдущая версия .
Re[101]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 15:24
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>аа.. я ориентировался на это
Автор: σ
Дата: 16.08.23


V>>Выше приводил конкретные 5 пунктов, даже с косвенной отсылкой на стандарт, посредством которых мною допускается гипотеза сабжевого UB. То есть, те 5 пунктов объясняют, каким образом допускается гипотеза про UB. Я не просил никаких ссылок на стандарт, наоборот, готов предоставить их явно для обоснования тех или иных своих тезисов. На счет того что "мне кажется" — тут да, мне действительно кажется что здесь может быть оттрактовано UB, и приведенные выше 5 пунктов объясняют каким именно образом.


R>Смотри, какая штука получается, давай еще раз посмотрим на этот абзац в стандарте:


R>https://timsong-cpp.github.io/cppwp/class.copy.elision#1


R>

R>When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object. If the first parameter of the selected constructor is an rvalue reference to the object's type, the destruction of that object occurs when the target would have been destroyed; otherwise, the destruction occurs at the later of the times when the two objects would have been destroyed without the optimization.


R>Object-то the same, но вот ways are different и это ключевой момент, который покрывает сразу и разницу времен жизни, и разницу в константности.


Время жизни является свойством объекта а не пути к нему. Время жизни определяется исходя из манипкляций с объектом, причем не важно сквозь какой путь. Поэтому, количество этих путей не важно. Объект один — lifetime один.

R> А еще хочу заострить внимание на вот этой фразе: "an implementation is allowed...". То есть, не говорится, что компилятор обязан так сделать — ему это разрешается. И как именно он поступит, так или эдак, программист даже знать не обязан. В итоге программист имеет полное право считать, что в данном случае создаются два (или даже три) объекта, с разными временами жизни и разной константностью.


Стандарт говорит по другому, ты сам чуть выше привел цитату про the same object. На практике это, например, будет проявляться в том что у программиста во внутреннем объекте и во внешнем — то ли одинаковый this (если случилось RVO) то ли разные (если оно не случилось). Так же, к примеру, побочные эффекты в выдавленных конструкторах поскипаются в случае RVO, а без него они останутся. Другими словами, программист не имеет права считать что бъекта будет два/три, он обязан считать что ему будет обстоятельствами непреодолимой силы (an implementation is allowed...) дадено либо два объекта либо один.

R>И правильно тут рядом сказали: NRVO — это разновидность оптимизации, как ни крути.


Ну.. Окей. Утверждение на любителя как по мне. По такой логике можно говорить что Zero-overhead principle, inline — это тоже разновидности оптимизации. Ну и что. Как это можно применить к сабжу?
Re[110]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 15:39
Оценка: :)
Здравствуйте, σ, Вы писали:

BFE>>Если это свойство выкидывается вместе с конструктором, то в коде примера ниже someDictionary вообще не начинает жить, а следовательно, const должен игнорироваться полностью, следовательно объект someDictionary можно менять (ведь его время жизни ещё не началось)


σ>

σ>https://timsong-cpp.github.io/cppwp/n4868/basic.life#7.sentence-4
σ>https://timsong-cpp.github.io/cppwp/n4868/res.on.objects#2

Вы не на то сослались
someDictionary вообще не начинает жить, а вот result — живёт вместо него и его можно менять используя переменную someDictionary.
И каждый день — без права на ошибку...
Re[109]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 15:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


V>>>> Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime

BFE>>> Ну попробуйте это обосновать.
V>>Ну, обоснование у меня вряд ли получится сформулировать. Вместо обоснования — приведу свою логику рассуждений:
V>>нет оснований полагать что в стандарте под выдавливанием copy пониматся не copy а некий "copy part", так как там не указано, какие именно аспекты copy будут выдавлены а какие — нет. Таким образом я считаю что имеется ввиду весь copy целиком.

BFE>lifetime — это не результат создания объекта. lifetime — это свойство объекта, присущее объекту в некоторые отрезки выполнения программы (от конца конструктора до начала деструктора).


ага

BFE>Если это свойство выкидывается вместе с конструктором, то в коде примера ниже someDictionary вообще не начинает жить


someDictionary не обладает свойством lifetime, потому что он не объект, someDictionary это имя объекта. А объект (помним что это тот самый объект который the same внутри и снаружи) означаемый именем someDictionary уже начал свой lifetime, когда внутри функции завершился конструктор result.

BFE>, а следовательно, const должен игнорироваться


так же смею заметить, константность объекта определяется не по конструктору, она определяется по декларации. А деклараций две, и хрен поймешь какую из них возьмет компилятор. В отсутствии каких либо предпосылок я предполагаю худший вариант, считаю что он возьмет ту которая внешняя, с констанностью (хотя выше по теме ув. σ показывал что и второй вариант — тоже проблемный). И вот в этом случае имеем константный объект (по декларации) с начатым временем жизни (внутри функции отработал конструктор, помним что этот объект the same), подвергается модификации.
Re[102]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 15:40
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>Ну.. Окей. Утверждение на любителя как по мне. По такой логике можно говорить что Zero-overhead principle, inline — это тоже разновидности оптимизации. Ну и что. Как это можно применить к сабжу?


Программист просто не обязан знать, применил ли компилятор NRVO, или не применил, и интерпретация деклараций и кода в целом не должна зависеть от таких деталей.
--
Справедливость выше закона. А человечность выше справедливости.
Re[111]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 15:43
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, σ, Вы писали:


BFE>>>Если это свойство выкидывается вместе с конструктором, то в коде примера ниже someDictionary вообще не начинает жить, а следовательно, const должен игнорироваться полностью, следовательно объект someDictionary можно менять (ведь его время жизни ещё не началось)


σ>>

σ>>https://timsong-cpp.github.io/cppwp/n4868/basic.life#7.sentence-4
σ>>https://timsong-cpp.github.io/cppwp/n4868/res.on.objects#2

BFE>Вы не на то сослались

BFE>someDictionary вообще не начинает жить, а вот result — живёт

Не забываем что someDictionary/result — это лишь имена, у них нет lifetime, они не живут. Lifetime есть только у объекта, который the same и доступен по обоим этим именам. Объект живет. Таким образом, наблюдаемый lifetime у the same object один и тот же независимо через какое имя мы смотрим на объект.
Re[103]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 15:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>Ну.. Окей. Утверждение на любителя как по мне. По такой логике можно говорить что Zero-overhead principle, inline — это тоже разновидности оптимизации. Ну и что. Как это можно применить к сабжу?


R>Программист просто не обязан знать, применил ли компилятор NRVO, или не применил, и интерпретация деклараций и кода в целом не должна зависеть от таких деталей.


именно так, для программиста этот исход не определен заранее. Аналогично программист не знает заранее, проинлайнит ли компилятор функцию или нет. Я с этим полностью согласен, это можно называть некоей "оптимизацией". Вопрос в другом: как это утверждение может помочь по сабжу (будет объект константным или нет
Автор: σ
Дата: 16.08.23
и затем — если он константный, будет ли UB при доступе к нему на запись после конструирования)?
Re[104]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 15:54
Оценка: +1 :)
Здравствуйте, vopl, Вы писали:

V>именно так, для программиста этот исход не определен заранее. Аналогично программист не знает заранее, проинлайнит ли компилятор функцию или нет. Я с этим полностью согласен, это можно называть некоей "оптимизацией". Вопрос в другом: как это утверждение может помочь по сабжу (будет объект константным или нет
Автор: σ
Дата: 16.08.23
и затем — если он константный, будет ли UB при доступе к нему на запись после конструирования)?


Помочь может очень легко: мы имеем полное право отвечать на эти вопросы в презумпции, что NRVO не примененяется (полагаю, ответы очевидны), а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 16:28 rg45 . Предыдущая версия . Еще …
Отредактировано 22.08.2023 15:55 rg45 . Предыдущая версия .
Re[105]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 16:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>именно так, для программиста этот исход не определен заранее. Аналогично программист не знает заранее, проинлайнит ли компилятор функцию или нет. Я с этим полностью согласен, это можно называть некоей "оптимизацией". Вопрос в другом: как это утверждение может помочь по сабжу (будет объект константным или нет
Автор: σ
Дата: 16.08.23
и затем — если он константный, будет ли UB при доступе к нему на запись после конструирования)?


R>Помочь может очень легко: мы имеем полное право отвечать на эти вопросы в презумции, что NRVO не примененяется (полагаю, ответы очевидны), а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.


Ну ок, пусть будет так. Я же останусь при мнении что нельзя считать что "NRVO не примененяется а если применяется то это не влияет на ...", так как в случае применения NRVO существуют явно наблюдаемая разница в поведении программы:
— выбрасываются побочные эффекты в конструкторе так как выбрасывается весь конструктор,
— this объекта будет одинаковый внутри функции и снаружи,
— объект будет один а не два (со всеми вытекающими)
Re[105]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 22.08.23 16:11
Оценка: :)
Ты хочешь сказать, что программа из well-defined может превратиться в ill-formed от простого изменения уровня оптимизации? Ты с головой дружишь вообще?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 16:33 rg45 . Предыдущая версия .
Re[105]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 16:13
Оценка: -1 :)
V>>именно так, для программиста этот исход не определен заранее. Аналогично программист не знает заранее, проинлайнит ли компилятор функцию или нет. Я с этим полностью согласен, это можно называть некоей "оптимизацией". Вопрос в другом: как это утверждение может помочь по сабжу (будет объект константным или нет
Автор: σ
Дата: 16.08.23
и затем — если он константный, будет ли UB при доступе к нему на запись после конструирования)?


R>Помочь может очень легко: мы имеем полное право отвечать на эти вопросы в презумции, что NRVO не примененяется (полагаю, ответы очевидны), а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.


А если взять что-нибудь типа
bool nrvo_didnt_happen;

struct S {
  S() = default;
  S(S&) { nrvo_didnt_happen = true; }
  S(S&&) { nrvo_didnt_happen = true; }
};
    
S f()
{
    S s;
    return s;
}

#include <iostream>

int main()
{
    S s = f();

    std::cout << nrvo_didnt_happen << '\n';
}

И спросить про вывод программы, ответ тоже будет
> мы имеем полное право отвечать на эти вопросы в презумции, что NRVO не примененяется, а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.
?
Re[106]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 16:16
Оценка:
Здравствуйте, σ, Вы писали:

BFE>>

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class
σ>object, even if the constructor selected for the copy/move operation and/or the destructor for the object
σ>have side effects. In such cases, the implementation treats the source and target of the omitted copy/move
σ>operation as simply two different ways of referring to the same object.


BFE>>Тут говорится, что реализация работает двумя различными путями с двумя объектами как с одним и тем же объектом. Здесь не утверждается, что объект один. Объектов два: "source and target".

σ>С чего ты решил, что source and target это объекты, а не (glvalue-)выражения или переменные?

Это следует из первого предложения:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

Речь идёт про объект.

σ>Дальше про source и target написано, что это «ways of referring to the same object».

σ>Что, скорее, является way of referring to an object: переменная/выражение или объект? Переменную или выражение вполне можно обозвать "способом ссылаться на объект". А называть объект "способом ссылаться на объект"? Ну ХЗ…
Ага. Nice copium, как вы говорите: как хочешь, так и понимай.

A variable is introduced by the declaration of a reference other than a non-static data member or of an object. The variable’s name, if any, denotes the reference or object.

Переменная, она не "referring to", она "denotes". Ну, это если формально подходить.

Я согласен, что source и target могут рассматриваться как переменные, но каждая переменная, если она не ссылка, декларирует свой объект. => два объекта.

BFE>> То, что эти операции опускаются, не означает, что объект один — формально объектов два

σ>Формально объект один, формально по-прежнему два способа на него ссылаться. Которые теперь ссылаются на один и тот же объект.
Нет, объектов два. Как вы себе представляете вызов конструктора копирования для самого себя? так: T t = t;? Уверяю вас, здесь речь не про этот случай. Речь идёт про конструктор копирования. Это когда один объект копируют в другой. Невозможно "omit" то, что не вызывается.

  Скрытый текст
BFE>>
σ>std::map<int, int> buildMap()
σ>{
σ>    std::map<int, int> result; // создали неконстантный объект result, после выполнения конструктора началось время жизни объекта result
σ>    result.insert(42, 43);     // изменили неконстантный объект result
σ>    return result;             // скопировали неконстантный объект result в возвращаемый неконстантный объект (*) - это операция пропускается
σ>                               //   после завершения конструктора временного объекта началось время жизни возвращаемого неконстантного объекта несмотря на то, что операция копирования была пропущена.
σ>                               // перед вызовом деструктора объекта result заканчивается время жизни объекта result
σ>                               // разрушили неконстантный объект result (*) - это операция пропускается
σ>}
σ>const std::map<int, int> someDictionary = buildMap(); // возвращаемый функцией buildMap() неконстантный объект передаётся в конструктор класса map             (*) - это операция пропускается 
σ>                                                      // внутри конструктора возвращаемый функцией buildMap() неконстантный объект перемещается (копируется)   (*) - это операция пропускается
σ>                                                      // после завершения выполнения конструктора                                                              (*) - это операция пропускается 
σ>                                                      //   началось время жизни константного объекта обозначаемого переменной someDictionary 
σ>                                                      // время жизни возвращаемого функцией buildMap() неконстантного объекта окончено  
σ>                                                      // после выполнения выражения возвращаемый функцией buildMap() неконстантный объект разрушается          (*) - это операция пропускается 
σ>

BFE>>- вот так (без подробностей) может выглядеть выполнение на абстрактной машине. Как видите время жизни константного объекта обозначаемого переменной someDictionary начинается после создания и модификации объекта.

σ>Ну ок, теперь я. Буду идти по sequenced before control flow-а. (Подразумевается C++17+, так что временных объектов нет в принципе, а не потому что copy elision)

σ>Встречаем definition const std::map<int, int> someDictionary ….

σ>Стандарт говорит в [intro.object]/1 «An object is created by a definition» и «The properties of an object are determined when the object is created», а в [basic.type.qualifier]/1 «The type of an object includes the cv-qualifiers specified in the decl-specifier-seq… when the object is created».
σ>decl-specifier-seq здесь это const std::map<int, int>, так что тип объекта const std::map<int, int> (ну, по крайней мере, тип точно включает в себя const, согласно цитате).

До вызова buildMap объект ещё не создан, а значит и свойства его ещё не определены.

σ>Дальше вызывается функция buildMap, где встречаем ещё один definition: std::map<int, int> result. Как описано выше, создаётся объект и назначаются его свойства, в частности, тип std::map<int, int>.

А ещё свойство lifetime.

σ>Когда у нас NRVO, мы второй раз определяем ему свойства одного и того же объекта, убрая const-квалификатор.

Вы уверены, что const — это свойство?

σ>Дальше надо решать, после которой инициализации мы начинаем лайфтайм. Допустим, после первой (закончившейся), для result.

Свою точку зрения на начало/конец лайфтайм я уже расписал.

σ>Ну а дальше объект так и остаётся с типом без const-квалификатора, т.к. его properties больше не determine ¯\_(ツ)_/¯

Ну т.е. его можно менять, как я рядом написал?
И каждый день — без права на ошибку...
Re[106]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 16:18
Оценка:
Здравствуйте, σ, Вы писали:

σ>И спросить про вывод программы, ответ тоже будет

>> мы имеем полное право отвечать на эти вопросы в презумции, что NRVO не примененяется, а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.
σ>?

А не пойти бы тебе куда подальше, вместе со своей демагогией? Разница на побочных эффектах существует на законных основаниях, ты сам прекрасно это знаешь, и это никак не порождает UB.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 16:19 rg45 . Предыдущая версия .
Re[112]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 16:28
Оценка:
Здравствуйте, vopl, Вы писали:

BFE>>someDictionary вообще не начинает жить, а вот result — живёт

V>Не забываем что someDictionary/result — это лишь имена, у них нет lifetime, они не живут.
someDictionary обозначает объект, который жить не начинал и он refering to объект result, который не константный. А значит const должен игнорироваться и объект можно менять.

V> Lifetime есть только у объекта, который the same и доступен по обоим этим именам. Объект живет. Таким образом, наблюдаемый lifetime у the same object один и тот же независимо через какое имя мы смотрим на объект.

Ага. Только вот объект создан неконстантным, а значит его можно менять через переменную someDictionary (в предположении, что const — это свойство).

Вы всё ещё не чувствуете, что это сведение к абсурду? Нет? Настаиваете, что это один и тот же объект?
И каждый день — без права на ошибку...
Re[106]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 22.08.23 16:43
Оценка: +1 -1
R>Ты хочешь сказать, что программа из well-defined может превратиться в ill-formed

ill-formed с UB спутал?

R>от простого изменения уровня оптимизации? Ты с головой дружишь вообще?


Ой...
Или здесь тоже законные основания побочных эффектов?
Re[113]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 16:50
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


BFE>>>someDictionary вообще не начинает жить, а вот result — живёт

V>>Не забываем что someDictionary/result — это лишь имена, у них нет lifetime, они не живут.
BFE>someDictionary обозначает объект, который жить не начинал и он refering to объект result, который не константный. А значит const должен игнорироваться и объект можно менять.

ну хз, звучит стремно
someDictionary обозначает объект, который ... refering to объект result. То есть, получается объект ссылается на объект. Тут не могу согласиться никак.

V>> Lifetime есть только у объекта, который the same и доступен по обоим этим именам. Объект живет. Таким образом, наблюдаемый lifetime у the same object один и тот же независимо через какое имя мы смотрим на объект.

BFE>Ага. Только вот объект создан неконстантным

по стандарту объект создается того типа который был при его декларации, а деклараций две, это явная коллизия, зря мы тут копья ломаем

BFE>, а значит его можно менять через переменную someDictionary (в предположении, что const — это свойство


по моим данным, "const" это часть свойства "тип" объекта, то есть, я бы ыполне употреблял выражение что const — это свойство объекта

BFE>).


BFE>Вы всё ещё не чувствуете, что это сведение к абсурду? Нет? Настаиваете, что это один и тот же объект?


Настаиваю что по формулировкам стандарта — это один объект. Чуствую что скоро будет иметь место какой нибудь дефект-репорт, типа "NRVO makes an object type collision ...blabla"
Re[114]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 16:57
Оценка:
Здравствуйте, vopl, Вы писали:

V>по стандарту объект создается того типа который был при его декларации, а деклараций две, это явная коллизия, зря мы тут копья ломаем


вот кстати, а эта хрень c the same object — она же нарушает ODR, так как объект один (если мы принимаем что он один) а определения два (в двух объявлениях) и они разные
Re[115]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 17:13
Оценка:
V>вот кстати, а эта хрень c the same object — она же нарушает ODR



ODR — это про переменные/типы/функции, ихние шаблоны и т.п., а не про объекты
Re[116]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 17:18
Оценка:
Здравствуйте, σ, Вы писали:

V>>вот кстати, а эта хрень c the same object — она же нарушает ODR


σ>


σ>ODR — это про переменные/типы/функции, ихние шаблоны и т.п., а не про объекты


ну так наш объект это ж и есть переменная, разве нет? https://timsong-cpp.github.io/cppwp/basic.pre#6
Re[115]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 17:20
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>>по стандарту объект создается того типа который был при его декларации, а деклараций две, это явная коллизия, зря мы тут копья ломаем

V>вот кстати, а эта хрень c the same object — она же нарушает ODR, так как объект один (если мы принимаем что он один) а определения два (в двух объявлениях) и они разные

Ещё один аргумент за то, что это два объекта, которые рассматриваются как один.
И каждый день — без права на ошибку...
Re[117]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 17:28
Оценка: +1
V>ну так наш объект это ж и есть переменная, разве нет?



Переменная это такая, как бы сказать, синтаксическая конструкция.
А объект — «рантайм»-штука. Ну, кроме как в константных выражениях, которые, как бы, компайл-тайм.

Переменная — всегда одна. А объектов, ассоциированных с ней, от 0 до бесконечности. В каждом, назовём так, контексте — свой.

V>https://timsong-cpp.github.io/cppwp/basic.pre#6


Это… надо уметь читать. Ну или переписать так, чтобы было понятно всем. Но переписывать отдельно не хотят.
Re[114]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 17:32
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>someDictionary обозначает объект, который ... refering to объект result. То есть, получается объект ссылается на объект. Тут не могу согласиться никак.

Так в стандарте так пишут.

V>по стандарту объект создается того типа который был при его декларации, а деклараций две, это явная коллизия, зря мы тут копья ломаем

По стандарту создаётся два объекта. По стандарту, в некоторых случаях, для двух объектов может быть проведена такая оптимизация вызовов деструкторов и конструкторов, что эти два объекта будут выглядеть как один.

V>Настаиваю что по формулировкам стандарта — это один объект. Чуствую что скоро будет иметь место какой нибудь дефект-репорт, типа "NRVO makes an object type collision ...blabla"

Не, ну вы серьёзно?
Это же классическая разница между "быть" и "выглядеть".
Вот здесь:

In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

treats as — это "рассматривать как", "обрабатывать как", "трактовать как", но не "быть" и не "являться".
И каждый день — без права на ошибку...
Re[118]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 17:35
Оценка:
Здравствуйте, σ, Вы писали:

V>>ну так наш объект это ж и есть переменная, разве нет?


σ>


σ>Переменная это такая, как бы сказать, синтаксическая конструкция.

σ>А объект — «рантайм»-штука. Ну, кроме как в константных выражениях, которые, как бы, компайл-тайм.

σ>Переменная — всегда одна. А объектов, ассоциированных с ней, от 0 до бесконечности. В каждом, назовём так, контексте — свой.


точно

V>>https://timsong-cpp.github.io/cppwp/basic.pre#6


σ>Это… надо уметь читать. Ну или переписать так, чтобы было понятно всем. Но переписывать отдельно не хотят.


судя по всему следует читать так: переменная вводится декларацией, у нас декларации две, сделовательно переменных две. То есть, это две разные переменные.
Re[115]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 22.08.23 17:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


V>>someDictionary обозначает объект, который ... refering to объект result. То есть, получается объект ссылается на объект. Тут не могу согласиться никак.

BFE>Так в стандарте так пишут.

где?

V>>Настаиваю что по формулировкам стандарта — это один объект. Чуствую что скоро будет иметь место какой нибудь дефект-репорт, типа "NRVO makes an object type collision ...blabla"

BFE>Не, ну вы серьёзно?

ага

BFE>Это же классическая разница между "быть" и "выглядеть".

BFE>Вот здесь:
BFE>

BFE>In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

BFE>treats as — это "рассматривать как", "обрабатывать как", "трактовать как", но не "быть" и не "являться".

все эти "трактовать как" относятся к source and target, а не к объекту. Либо я не понял суть момента
Re[106]: Когда это наконец станет defined behavior?
От: T4r4sB Россия  
Дата: 22.08.23 17:48
Оценка:
Специально для троллей-демагогов, склонных читать стандарт, не понимая значения слов в зависимости от контекста, я принёс UB покруче:

#include <stdio.h>
#include <stdlib.h>

struct T { int i; };

void foo(const int* i, struct T* t) {
    int i1 = *i;
    printf("i1=%i\n", i1);
    *t = {42};
    int i2 = *i;
    printf("i2=%i\n", i2);
}

int main() {
    struct T t {1337};
    foo(&t.i, &t);
    return 0;
}

Одна и та же область памяти одновременно занята и типом int, и типом struct T! Это же нарушение правила strict aliasing!!! И пусть все компиляторы даже с -O3 читают значение по адресу i дважды, но это же на самом деле UB!!! Я высрал такой вывод, прочитав стандарт и поняв его по-своему!!!
А теперь докажите мне, со ссылками на стандарт, что в будущем ни один компилятор не соптимизирует этот код, выкинув второе чтение из памяти. А я буду строить из себя дурачка и тыкать в стандарт с тупым лицом.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[105]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 17:54
Оценка:
Здравствуйте, rg45, Вы писали:

R>Помочь может очень легко: мы имеем полное право отвечать на эти вопросы в презумпции, что NRVO не примененяется (полагаю, ответы очевидны), а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.


применение NRVO выкидывает даже side эффекты, так что ожидать можно чего угодно.
И каждый день — без права на ошибку...
Re[106]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 18:08
Оценка:
Здравствуйте, σ, Вы писали:

σ>А если взять что-нибудь типа

σ>
bool nrvo_didnt_happen;

σ>struct S {
σ>  S() = default;
σ>  S(S&) { nrvo_didnt_happen = true; }
σ>  S(S&&) { nrvo_didnt_happen = true; }
σ>};
    
σ>S f()
σ>{
σ>    S s;
σ>    return s;
σ>}

σ>#include <iostream>

σ>int main()
σ>{
σ>    S s = f();

σ>    std::cout << nrvo_didnt_happen << '\n';
σ>}

σ>И спросить про вывод программы, ответ тоже будет
>> мы имеем полное право отвечать на эти вопросы в презумции, что NRVO не примененяется, а применение NRVO, если таковое произошло, никак не должно повлиять на рассуждения и выводы.
σ>?

Это пример не интересный, его надо усложнить добавив вызовов f():
int main()
{
        nrvo_didnt_happen = false;
    S s1 = f();
    std::cout << nrvo_didnt_happen;
        nrvo_didnt_happen = false;
    S s2 = f();
    std::cout << nrvo_didnt_happen;
        nrvo_didnt_happen = false;
    S s3 = f();
    std::cout << nrvo_didnt_happen;
}


Если вы думает, что стандарт гарантирует вывод 111 или 000, то вы ошибаетесь. Могут быть все 8 вариантов 000, 001, 010, 011, ... 111
И каждый день — без права на ошибку...
Re[107]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 22.08.23 18:10
Оценка:
Здравствуйте, σ, Вы писали:

σ>Ой...

σ>Или здесь тоже законные основания побочных эффектов?

Главное — побольше смайликов. Это безусловно демонстрирует твое превосходство.
--
Справедливость выше закона. А человечность выше справедливости.
Re[107]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 22.08.23 18:14
Оценка: :)
Здравствуйте, σ, Вы писали:

R>>Ты хочешь сказать, что программа из well-defined может превратиться в ill-formed


σ>ill-formed с UB спутал?


ill-formed программа не обязательно порождает UB, но программа, порождающая UB — обязательно ill-formed. Иди логику учи, дядя.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 18:29 rg45 . Предыдущая версия . Еще …
Отредактировано 22.08.2023 18:21 rg45 . Предыдущая версия .
Re[116]: Когда это наконец станет defined behavior?
От: B0FEE664  
Дата: 22.08.23 18:24
Оценка:
Здравствуйте, vopl, Вы писали:

V>>>someDictionary обозначает объект, который ... refering to объект result. То есть, получается объект ссылается на объект. Тут не могу согласиться никак.

BFE>>Так в стандарте так пишут.
V>где?

The variable’s name, if any, denotes the reference or object.

И, если source and target — имена переменных, как меня путаются убедить, то "referring to":

In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


BFE>>Не, ну вы серьёзно?

V>ага
Без меня.

BFE>>Это же классическая разница между "быть" и "выглядеть".

BFE>>Вот здесь:
BFE>>

BFE>>In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

BFE>>treats as — это "рассматривать как", "обрабатывать как", "трактовать как", но не "быть" и не "являться".

V>все эти "трактовать как" относятся к source and target, а не к объекту. Либо я не понял суть момента

Да, к source and target. И эти source and target "трактуются как" два пути к одному и тому же объекту, а на самом деле это два пути, к двум разным объектам и операция копирования из одного объекта в другой выброшена.
И каждый день — без права на ошибку...
Re[108]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 22.08.23 18:52
Оценка:
R>программа, порождающая UB — обязательно ill-formed

Хуясе новости.
Re[109]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 22.08.23 18:54
Оценка:
Здравствуйте, σ, Вы писали:

R>>программа, порождающая UB — обязательно ill-formed


σ>Хуясе новости.


С разморозкой

А ты допускаешь существование well-defined программы, порождающей UB ? Растешь прямо на глазах.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 22.08.2023 18:56 rg45 . Предыдущая версия .
Re[107]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 19:21
Оценка:
σ>>С чего ты решил, что source and target это объекты, а не (glvalue-)выражения или переменные?
BFE>Это следует из первого предложения:
BFE>

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

BFE>Речь идёт про объект.
Причём, про один. Значит, из первого предложения следует, что объект один.
Столько же логики, как в том, что из первого предложения следует, что source и target — это объект. (Примерно ноль.)

σ>>Дальше про source и target написано, что это «ways of referring to the same object».

σ>>Что, скорее, является way of referring to an object: переменная/выражение или объект? Переменную или выражение вполне можно обозвать "способом ссылаться на объект". А называть объект "способом ссылаться на объект"? Ну ХЗ…
BFE>Ага. Nice copium, как вы говорите: как хочешь, так и понимай.

Copium — это делать вид, что "объект это способ ссылаться на объект" нормальное словоупотребление.

BFE>

A variable is introduced by the declaration of a reference other than a non-static data member or of an object. The variable’s name, if any, denotes the reference or object.

BFE>Переменная, она не "referring to", она "denotes". Ну, это если формально подходить.
Если формально подходить, denotes курсивом не выделено, т.е. это не термин, а обычное слово. И вместо него могут использоваться (и используются, искать влом) синонимы. "referring to", "names" — вполне себе (контекстуальные) синонимы для "denotes". (Нет, мне не нравится ни одно из этих слов, я бы ввёл термин, но это уже оффтоп)

BFE>>> То, что эти операции опускаются, не означает, что объект один — формально объектов два

σ>>Формально объект один, формально по-прежнему два способа на него ссылаться. Которые теперь ссылаются на один и тот же объект.
BFE> Нет, объектов два. Как вы себе представляете вызов конструктора копирования для самого себя? так: T t = t;? Уверяю вас, здесь речь не про этот случай. Речь идёт про конструктор копирования. Это когда один объект копируют в другой. Невозможно "omit" то, что не вызывается.

Есть два экземпляра абстрактной машины (точнее, два возможных выполнения): в одном NRVO применяется, в другом — нет.
Во второй вызывается конструктор копирования. В первой — нет. Получается "omit" по сравнению со второй.

σ>>Ну ок, теперь я. Буду идти по sequenced before control flow-а. (Подразумевается C++17+, так что временных объектов нет в принципе, а не потому что copy elision)


σ>>Встречаем definition const std::map<int, int> someDictionary ….

σ>>Стандарт говорит в [intro.object]/1 «An object is created by a definition» и «The properties of an object are determined when the object is created», а в [basic.type.qualifier]/1 «The type of an object includes the cv-qualifiers specified in the decl-specifier-seq… when the object is created».
σ>>decl-specifier-seq здесь это const std::map<int, int>, так что тип объекта const std::map<int, int> (ну, по крайней мере, тип точно включает в себя const, согласно цитате).

BFE>До вызова buildMap объект ещё не создан, а значит и свойства его ещё не определены.


Что скажешь про void* p = &p;? До после ; тоже объект ещё не создан? И что тогда можно сказать про &p?

σ>>Дальше вызывается функция buildMap, где встречаем ещё один definition: std::map<int, int> result. Как описано выше, создаётся объект и назначаются его свойства, в частности, тип std::map<int, int>.

BFE>А ещё свойство lifetime.
А что с ним такого особенного? До начала lifetime объект… вне lifetime. Что тут обсуждать?

σ>>Когда у нас NRVO, мы второй раз определяем ему свойства одного и того же объекта, убрая const-квалификатор.

BFE>Вы уверены, что const — это свойство?
Ой-вей. Тип объекта это его свойство. Я думал будет понятно, какие слова были опущены. На всякий случай:
> мы второй раз определяем ему свойства одного и того же объекта, убрая const-квалификатор из его типа.

На ещё всякий случай: это я так описал смену типа с const map<> на map<>

σ>>Ну а дальше объект так и остаётся с типом без const-квалификатора, т.к. его properties больше не determine ¯\_(ツ)_/¯

BFE>Ну т.е. его можно менять, как я рядом написал?
Про то, что если объект неконстантный, то его можно менять и вне функции я писал ещё в https://rsdn.org/forum/cpp/8583578.1
Автор: σ
Дата: 18.08.23
Re[107]: Когда это наконец станет defined behavior?
От: σ  
Дата: 22.08.23 19:23
Оценка:
BFE>Могут быть все 8 вариантов 000, 001, 010, 011, ... 111
Для этого в [class.copy.elision] должно присутствовать кое-какое слово, которого там нет. Ты заметил это?
  Скрытый текст
Я бы сказал, это дефект
Re[108]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 19:32
Оценка:
Здравствуйте, σ, Вы писали:

σ>Я бы сказал, это дефект


А просто сказать и не вые..ваться религия не позволяет?
--
Справедливость выше закона. А человечность выше справедливости.
Re[108]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 22.08.23 20:55
Оценка:
Здравствуйте, σ, Вы писали:

σ>Для этого в [class.copy.elision] должно присутствовать кое-какое слово, которого там нет. Ты заметил это?

σ>Я бы сказал, это дефект

А если это дефект, тогда к чему была эта
Автор: σ
Дата: 16.08.23
интрига? Вообще ведь ни вкассу, ни в лужу. Порисоваться приспичило, что ли?
--
Справедливость выше закона. А человечность выше справедливости.
Re[109]: Когда это наконец станет defined behavior?
От: so5team https://stiffstream.com
Дата: 23.08.23 07:33
Оценка: +1 :))
Здравствуйте, rg45, Вы писали:

σ>>Для этого в [class.copy.elision] должно присутствовать кое-какое слово, которого там нет. Ты заметил это?

σ>>Я бы сказал, это дефект

R>А если это дефект, тогда к чему была эта
Автор: σ
Дата: 16.08.23
интрига? Вообще ведь ни вкассу, ни в лужу. Порисоваться приспичило, что ли?


Выглядит это так: "Зубрите стандарт! Зубрите стандарт! Зубрите стандарт! Ну что вызубрили? А теперь смотрите: здесь слово пропущено!!!"

Вспоминается "Тот, кто лечится по медицинскому справочнику, рискует умереть от опечатки."
Re[108]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 07:38
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, σ, Вы писали:


R>>>Ты хочешь сказать, что программа из well-defined может превратиться в ill-formed


σ>>ill-formed с UB спутал?


R>ill-formed программа не обязательно порождает UB, но программа, порождающая UB — обязательно ill-formed. Иди логику учи, дядя.


cppreference.com считает что
1. ill-formed в этом случае нужно обязательно брать с пометкой no diagnostic required, и такая штука существенно отличается от просто ill-formed (который явно диагностирует проблему)
2. причинность ровно наоборот, не "UB -> ill-formed, no diagnostic required", а "ill-formed, no diagnostic required -> UB". То есть, во множестве UB есть такие, которые не являются "ill-formed, no diagnostic required"
Re[109]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 08:00
Оценка: :))
Здравствуйте, vopl, Вы писали:

V>cppreference.com считает что

V>1. ill-formed в этом случае нужно обязательно брать с пометкой no diagnostic required, и такая штука существенно отличается от просто ill-formed (который явно диагностирует проблему)

А стандарт языка говорит, что

https://timsong-cpp.github.io/cppwp/intro.defs#defns.ill.formed

3.25
ill-formed program
program that is not well-formed


В свою очередь well-formed программа не может порождать неопределенное поведение, по определению: https://timsong-cpp.github.io/cppwp/intro.defs#defns.well.formed. И "diagnostics required" никакой погоды не делает в этом контексте.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 9:02 rg45 . Предыдущая версия . Еще …
Отредактировано 23.08.2023 8:56 rg45 . Предыдущая версия .
Re[117]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 23.08.23 08:50
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, vopl, Вы писали:


V>>>>someDictionary обозначает объект, который ... refering to объект result. То есть, получается объект ссылается на объект. Тут не могу согласиться никак.

BFE>>>Так в стандарте так пишут.
V>>где?
BFE>

BFE>The variable’s name, if any, denotes the reference or object.

BFE>И, если source and target — имена переменных, как меня путаются убедить, то "referring to":
BFE>

BFE>In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


то есть,
source is a variable name, source referring to the object
target is a variable name, target referring to the same object

и нигде нет такого что "объект ссылается на объект"

BFE>>>Не, ну вы серьёзно?

V>>ага
BFE>Без меня.

BFE>>>Это же классическая разница между "быть" и "выглядеть".

BFE>>>Вот здесь:
BFE>>>

BFE>>>In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.

BFE>>>treats as — это "рассматривать как", "обрабатывать как", "трактовать как", но не "быть" и не "являться".

V>>все эти "трактовать как" относятся к source and target, а не к объекту. Либо я не понял суть момента

BFE>Да, к source and target. И эти source and target "трактуются как" два пути к одному и тому же объекту, а на самом деле это два пути, к двум разным объектам и операция копирования из одного объекта в другой выброшена.

Услышал. Ну, не знаю. Субъективно все это. Лично мне кажется что логику надо применять такую
1. выдавливается копирование
2. после того как оно выдавлено — теряет смысл наличие двух объектов, соответственно выдавливается эта двойственность
3. остается просто один объект

ну, опять же, это уже область сугубо субъективного, никаких доводов в пользу моей трактовки у меня нет

считаю вопрос исчерпаным, с формулировкой "не договорились"
Re[110]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 09:02
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>cppreference.com считает что

V>>1. ill-formed в этом случае нужно обязательно брать с пометкой no diagnostic required, и такая штука существенно отличается от просто ill-formed (который явно диагностирует проблему)

R>А стандарт языка говорит, что


R>https://timsong-cpp.github.io/cppwp/intro.defs#defns.ill.formed


R>

R>3.25
R>ill-formed program
R>program that is not well-formed


R>В свою очередь well-formed программа не может порождать неопределенное поведение, по определению: https://timsong-cpp.github.io/cppwp/intro.defs#defns.well.formed. И "diagnostic required" никакой погоды не делает в этом контексте.


по определению, well-formed программа всего лишь
1. не нарушает синтаксис
2. не нарушает правила семантики

для того чтобы увязать это с неопределенным поведением — надо проделать еще какие то шаги, одного только представленного определения не достаточно, так как в нем нет ни слова о неопределенном поведении
Re[111]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 09:06
Оценка:
Здравствуйте, vopl, Вы писали:

V>для того чтобы увязать это с неопределенным поведением — надо проделать еще какие то шаги, одного только представленного определения не достаточно, так как в нем нет ни слова о неопределенном поведении


Вообще-то есть: "C++ program constructed according to the syntax and semantic rules". Конечно, здесь подразумевается, что мы знаем, что такое неопределенное поведение: https://timsong-cpp.github.io/cppwp/intro.defs#defns.undefined: "behavior for which this document imposes no requirements...". Два эти пункта исключают возможность порождения UB в well-formed программе. А программа, если она не well-formed, она ill-formed — также по определению. ЧТД.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 9:13 rg45 . Предыдущая версия . Еще …
Отредактировано 23.08.2023 9:12 rg45 . Предыдущая версия .
Re[112]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 10:19
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>для того чтобы увязать это с неопределенным поведением — надо проделать еще какие то шаги, одного только представленного определения не достаточно, так как в нем нет ни слова о неопределенном поведении


R>Вообще-то есть: "C++ program constructed according to the syntax and semantic rules". Конечно, здесь подразумевается, что мы знаем, что такое неопределенное поведение: https://timsong-cpp.github.io/cppwp/intro.defs#defns.undefined: "behavior for which this document imposes no requirements...". Два эти пункта исключают возможность порождения UB в well-formed программе. А программа, если она не well-formed, она ill-formed — также по определению. ЧТД.


ну, хз, как то звучит натянуто.. Я бы на этот вопрос заходил с другой стороны, например со стороны требований к программе, ее частям и выполнению, в частности, пункт о нарушении недиагностируемых правил, из которого следует отсутствие требований к компилятору в отношении программы, в частности, к ее исполнению. Затем такое отсутствие требований можно трактовать как неопределенность поведения (по его определению).

То есть, получается:
ill-formed, no diagnostic is required — это нарушение недиагностируемого правила
нарушение недиагностируемого правила — приводик к снятию всех требований к исполнению программы
такое отсутствие требований определяется как UB

При этом, обрати внимание, просто ill-formed (без no diagnostic is required) — это следующий пункт. Там не идет речи о снятии каких либо требований, то есть, не получится выйти на какой то UB. Там постулируется просто что должен быть выброшен хотя бы один диагностирующий мессэдж и все.
Re[110]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 10:49
Оценка:
Здравствуйте, rg45, Вы писали:

R>В свою очередь well-formed программа не может порождать неопределенное поведение


вот пример программы, которая well-formed и производит UB одновременно

int main(int argc, char* argv[])
{
    return argc+220;//при достаточно больших argc имеем UB вследствие переполнения инта
}
Re[111]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 11:10
Оценка:
Здравствуйте, vopl, Вы писали:

V>вот пример программы, которая well-formed и производит UB одновременно


V>
V>int main(int argc, char* argv[])
V>{
V>    return argc+220;//при достаточно больших argc имеем UB вследствие переполнения инта
V>}
V>


Программа, порождающая UB, не может быть well-formed по определению. Well-formed программа могла бы выглядеть, например, как-то так:

int main(int argc, char* argv[])
{
    return argc <= std::numeric_limits<int>::max() - 220 ? argc + 220 : LOGIC_ERROR_CONSTANT;
}


Ну или накрайняк вот так:

int main(int argc, char* argv[])
{
    return int(unsigned(argc) + 220U);
}
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 11:42 rg45 . Предыдущая версия . Еще …
Отредактировано 23.08.2023 11:14 rg45 . Предыдущая версия .
Re[112]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 11:18
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>вот пример программы, которая well-formed и производит UB одновременно


V>>
V>>int main(int argc, char* argv[])
V>>{
V>>    return argc+220;//при достаточно больших argc имеем UB вследствие переполнения инта
V>>}
V>>


R>Нет, это как раз-таки пример ill-formed программы.


никакое правило тут не нарушено. Покажи, какое правило тут нарушено? Что именно делает программу ill-formed?

R>Well-defined программа должна выглядеть как-то так:

R>
R>int main(int argc, char* argv[])
R>{
R>    return argc <= std::numeric_limits<int>::max() - 220 ? argc + 220 : LOGIC_ERROR_CONSTANT;
R>}
R>
Re[113]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 11:46
Оценка:
Здравствуйте, vopl, Вы писали:

V> никакое правило тут не нарушено. Покажи, какое правило тут нарушено? Что именно делает программу ill-formed?


Эта программа порождает UB. Программа, порождающая UB, не может быть well-formed по определению: 3.25, 3.65, 3.68.
--
Справедливость выше закона. А человечность выше справедливости.
Re[104]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 23.08.23 12:11
Оценка:
Здравствуйте, vopl, Вы писали:

V>внешнее и внутреннее имена трактуются как если они ссылаются на один и тот же объект. Тогда время жизни объекта, означенного внешнем именем — трактуется как время жизни как будто бы "того же объекта". То есть, не важно как мы эту штуку назовем — один и тот же объект, или "нечто трактуемое как один и тот же объект" — все эффекты около этой штуки будут одинаковыми в обоих случаях.


Ну да, на вызывающей стороне это неотличимо, т.е., если логику buildMap вставить в конструктор некоего наследника, то будет идентичный код для такой инициализации:
const MyMap map = MyMap();

Т.е. точно так же на вызывающей стороне будет выделено место в локальной памяти под объект и адрес этой памяти будет передан аргументом в конструктор.
В этом смысле вызов конструктора неотличим от вызова фабричной ф-ии, возвращающей объект по значению (с применённым RVO).


V>Более того, эти два подхода не различимы, не возможно определить, имеем мы дело с "одним и тем же объектом" или с чемто, "с чем работать нужно как с одним и тем же"


В старых компиляторах в сниппете вызывался конструктор копирования, в более новых до C++17 применялось copy elision, теперь это всё просто называют prvalue, которое рекомендуют не материализовать без лишней необходимости.

Но семантика не поменялась — как и прежде доступ к константной переменной map возможен только после окончания инициализации объекта.
И если конструктор был без побочных эффектов вокруг this, то в наличии у нас будет только константная отсылка к объекту.

То бишь, после появления сущности-константы, уже невозожно без доп.хаков достичь обсуждаемого UB.
Re[110]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 23.08.23 12:31
Оценка: +2
R>стандарт языка говорит, что

R>https://timsong-cpp.github.io/cppwp/intro.defs#defns.ill.formed


R>

3.25
ill-formed program
program that is not well-formed


R>В свою очередь well-formed программа не может порождать неопределенное поведение, по определению: https://timsong-cpp.github.io/cppwp/intro.defs#defns.well.formed


Now I read:

well-formed program
C++ program constructed (emphasis mine) according to the syntax and semantic rules

Если программа constructed according to the syntax and semantic rules , а нарушение semantic rules, или ещё что-то подходящее под определение UB, возникнет во время её execution, то это никак не отменит well-formed
Отредактировано 23.08.2023 12:33 σ . Предыдущая версия . Еще …
Отредактировано 23.08.2023 12:32 σ . Предыдущая версия .
Re[114]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 12:43
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>> никакое правило тут не нарушено. Покажи, какое правило тут нарушено? Что именно делает программу ill-formed?


R>Эта программа порождает UB. Программа, порождающая UB, не может быть well-formed по определению: 3.25, 3.65, 3.68.


Прикалуешся что ли? Масло маслянное. Ну ладно, давай по твоему, с твоей стороны зайдем.
Исходно имеем следующее определение well-formed программы:

C++ program constructed according to the syntax and semantic rules

ты заявляешь что предъявленная программа не является well-formed так как содержит UB. (напомню программу: int main(int argc, char*[]){return argc+220;}).
Для того чтобы такое следствие было истинным — следует полагать, что наличие UB — ломает according to the syntax and semantic rules.
Помним, что UB есть ни что иное как упразднение требований к поведению (программы).

в этом контексте вопрос: каким именно образом факт упразднения требований к программе (UB) приводит к нарушению каких либо синтаксических/семантических правил, на основании которых построена программа (well-formed)?
этот же вопрос, другая формулировка: какие именно синтаксические/семантические правила, в соответствии с которыми построена программа, нарушаются по факту упразднения требований к программе?
этот же вопрос, в упрощенной форме: покажи, какое именно правило нарушено в приведенной программе?

---------------------------------------------
или вообще можно с другой стороны зайти. Вот обрати внимание на пояснительную записку к UB:

undefined behavior
behavior for which this document imposes no requirements
[Note 1: Undefined behavior may be expected when
— this document omits any explicit definition of behavior or
— when a program uses an erroneous construct or
erroneous data.
... далее поскипано неважное


в ней говорится что UB можно ожидать в случае erroneous data. Это рантайм. При этом, все те rules, в соответствии с которыми строится well-formed программа — они имеют место ДО рантайма. Но ничто более позднее (UB в рантайме по причине erroneous data) не может быть причиной более раннему (syntax and semantic rules). То есть, существуют такие UB, которые не ломают well-formed программу в ill-formed так как существуют после того как программа приобрела свойство well-formed. То есть, следующий тезис не верен: "Программа, порождающая UB, не может быть well-formed".
Re[115]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 23.08.23 12:48
Оценка: +1
V>UB есть ни что иное как упразднение требований к поведению (программы).
  Скрытый текст
Если совсем строго, то реализации, ибо https://timsong-cpp.github.io/cppwp/n4868/intro.scope#1.sentence-1. А «поведение программы не определено» это более краткая/удобная форма записи «поведение реализации по отношению к программе не опеределено». Ну это так, на правах FYI
Отредактировано 23.08.2023 12:49 σ . Предыдущая версия .
Re[115]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 12:50
Оценка: :))
Здравствуйте, vopl, Вы писали:

V>Исходно имеем следующее определение well-formed программы:

V>

C++ program constructed according to the syntax and semantic rules

V>ты заявляешь что предъявленная программа не является well-formed так как содержит UB. (напомню программу: int main(int argc, char*[]){return argc+220;}).
V>Для того чтобы такое следствие было истинным — следует полагать, что наличие UB — ломает according to the syntax and semantic rules.

Конечно ломает: 3.65. "behavior for which this document imposes no requirements" не сомещается с "according to the syntax and semantic rules".
--
Справедливость выше закона. А человечность выше справедливости.
Re[111]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 12:52
Оценка: :))
Здравствуйте, σ, Вы писали:

σ>Если программа constructed according to the syntax and semantic rules , а нарушение semantic rules, или ещё что-то подходящее под определение UB, возникнет во время её execution, то это никак не отменит well-formed


Если "возникнет", значит "not constructed according..." — все просто.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 12:52 rg45 . Предыдущая версия .
Re[112]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 23.08.23 12:56
Оценка:
R>Если "возникнет", значит "not constructed according" — все просто.

Притащи constructed-level правило, по которому программа должна быть такой, чтобы ни для каких входных данных не могло "возникнуть" UB [во время выполнения].
Re[116]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 12:57
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>Исходно имеем следующее определение well-formed программы:

V>>

C++ program constructed according to the syntax and semantic rules

V>>ты заявляешь что предъявленная программа не является well-formed так как содержит UB. (напомню программу: int main(int argc, char*[]){return argc+220;}).
V>>Для того чтобы такое следствие было истинным — следует полагать, что наличие UB — ломает according to the syntax and semantic rules.

R>Конечно ломает: 3.65. "behavior for which this document imposes no requirements" не сомещается с "according to the syntax and semantic rules".


ну и я говорю что ломает. Да, я делаю именно такую предпосылку. Это преамбула, читай сообщение в целом, не кусками. Там дальше будут вопросы, лучше на них ответь.
Re[106]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 23.08.23 12:58
Оценка:
Здравствуйте, vopl, Вы писали:

V>так нельзя, все эти "делаем вид" должны иметь обоснование, а его нет.


Вообще-то обоснование есть и про него говорили с самого начала (рассуждения про побочные эффекты).


V>Выдавлен copy — значит его эффект стал пустым.


Но это не само в компиляторах произошло, а через многолетнюю серию обсуждений сообщества С++, где сообщество в конце всех концов пришло к консенсусу, что конструктор копирования желательно рассматривать как имеющий пустой побочный эффект, аналогично насчёт деструкторов.

Разумеется, такая интерпретация конструктора копирования ломает некоторые старые программы, в которых побочные эффекты конструкторов копирования были необходимы для корректной работы, но сообщество С++ пошло на этот шаг, принеся "свободу делать что хочу" в жертву оптимальности при всё еще достаточной выразительности.

В общем, это был достаточно болезненный шаг и одна из причин, почему фиксация стандарта С++11 настолько затянулась (более 5-ти лет! изначально тот стандарт должен был выйти в нулевые, его так и называли предварительно — C++0x)

Из предисловия к "Язык программирования С++", 4 ред.:

С годами использование C++ сильно изменилось, как и сам язык. С точки зрения программиста, большинство изменений были улучшениями. Текущий стандарт ISO C++ (ISO/IEC 14882:2011, обычно называемый C++11) — это просто гораздо лучший инструмент для написания качественного программного обеспечения, чем предыдущие версии. Насколько это лучший инструмент? Какие стили и приемы программирования поддерживает современный C++? Какие функции языка и стандартной библиотеки поддерживают эти методы? Каковы основные строительные блоки элегантного, правильного, поддерживаемого и эффективного кода C++? Вот основные вопросы, на которые отвечает эта книга. Многие ответы отличаются от тех, которые вы могли бы найти в C++ 1985, 1995 или 2005 года выпуска: прогресс происходит.


От себя добавлю, что в С++ намного больше здравого смысла, чем может показаться при поверхностном взгляде.
Для любого решения, принятого в языке, есть тонны обснований — многолетних обсуждений + миллионы строк наработанной практики.

(например, конструкторы перемещения эмулировались задолго до появления в стандарте, у нас в конторе аналоги exception_ptr были для стандарта С++03, для него же promise/future и т.д. и т.п.)


V>Нет оснований полагать, что copy elision относится только к части copy. Он относится ко всему copy целиком, со всеми его эффектами, включая связность с lifetime


Разумеется.
В этом и состоит консенсус, что, согласно синтаксиса и семантики программы, copy constructor присутствует и вызывается (я же предлагал попытаться провернуть тот же трюк при недоступном конструкторе копирования), но компилятору разрешается опускать конструкторы копирования/перемещения, считая их как если бы они не содержали побочных эффектов — в этом случае гарантируется соблюдение семантики исходника в рантайме.

Если же ты в конструкторы копирования вставишь, допустим, логгирование (побочный эффект, а так же вставить логгирование в деструктор), то сохранение семантики программы уже НЕ гарантируется.

В общем, это был сознательный шаг.
Но одновременно с этим были выработаны определённые шаблоны проектирования для объектов, имеющих подобные побочные эффекты при конструировании/разрушении:
— у таких объектов запрещены конструкторы копирования/перемещения/operator= (примечание: такие конструкторы, конечно, могут существовать в прикладных целях, но их стоит объявлять как explicit и/или приватными/защищёнными);
— в качестве бонуса зато можно пользоваться адресом объекта как его identity из ООП-парадигмы (т.е. защитив объект от "случайного" перемещения или копирования).

=================================
ИМХО, бесполезно изучать С++ через стандарт.

Стандарт может и должен использоваться сугубо как справочник, но он не подскажет приёмы/техники/шаблоны проектирования, ради которых стандарт именно таков, какой он есть.
Т.е. стандарт — это как готовый ответ без постановки задачи, бгг.

- Петька, приборы!
— 42!
— Что "42"?
— А что "приборы"?


Разумеется, в пределе аналитических скилов стандарт может "подсказать" исходную постановку задачи, если знать стандарт наизусть и держать его в памяти целиком, но это не самый эффективный путь, ес-но. ))

Именно поэтому я неоднократно призывал плясать не от определения UB, а от сценариев, где оно может себя проявить.

Иначе возникают спекуляции, как у вас, где вы запросто рассуждаете о том, что константный объект уже определён, хотя он нифига не определён. ))
Определён экземпляр объекта через трюк RVO — OK, но этот экземпляр в некоторой фазе исполнения программы недоступен для манипуляции через целевую константу.

Соответственно, в рассматриваемой фазе инициализации, когда еще нет доступа к объекту через константу, у этой константы не может быть вообще никакого "поведения", не то что "неопределённого", по поводу которого вы высказывали беспокойство. ))
Отредактировано 23.08.2023 17:17 vdimas . Предыдущая версия .
Re[113]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 13:00
Оценка: :)
Здравствуйте, σ, Вы писали:

R>>Если "возникнет", значит "not constructed according" — все просто.


σ>Притащи constructed-level правило, по которому программа должна быть такой, чтобы ни для каких входных данных не могло "возникнуть" UB [во время выполнения].


Правила соблюдаются только тогда, когда они соблюдаются всегда. Если правила иногда соблюдаются, а иногда нет, то это просто правила не соблюдаются. Опять все просто.
--
Справедливость выше закона. А человечность выше справедливости.
Re[117]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 13:03
Оценка: :)
Здравствуйте, vopl, Вы писали:

V>Там дальше будут вопросы, лучше на них ответь.


А мне не нужно "дальше", мне достаточно того, что я уже увидел. Я вообще считаю, что если человек не способен сформулировать свою мысль одним четким копактным абзацем, то в голове у него путаница. И бродить по этим лабиринтам сознания у меня мотивации ноль.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 13:05 rg45 . Предыдущая версия .
Re[114]: Че ты лыбишься, хам трамвайный?
От: σ  
Дата: 23.08.23 13:13
Оценка:
R>>>Если "возникнет", значит "not constructed according" — все просто.

σ>>Притащи constructed-level правило, по которому программа должна быть такой, чтобы ни для каких входных данных не могло "возникнуть" UB [во время выполнения].


R>Правила соблюдаются только тогда, когда они соблюдаются всегда. Если правила иногда соблюдаются, а иногда нет, то это просто правила не соблюдаются. Опять все просто.


Правила есть разные, и последствия от их нарушения тоже разные. Какие-то нарушения делают программу ill-formed, какие-то — не делают.

Короче. Чтобы долго воду в ступе не толочь (как ты любишь).
Я думаю, я знаю что в твоей склерозной кочерыжке с чем смешалось.
В C есть понятие strictly confirming program:
> A strictly conforming program shall use only those features of the language and library specified in this International Standard. It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit.

Предполагаю, ты это где-то когда-то видел, и чёт там такое запомнил про отсутствие UB для любого возможного input, чтобы программа считалась «очень хорошей», но…

Ток вот C++ — не C. В нём нет ни понятия «strictly conforming program», ни правила, что [для того, чтобы быть well-formed] в программе не должно возникать UB [во время выполнения] ни для какого возможного input.
Отредактировано 23.08.2023 13:13 σ . Предыдущая версия .
Re[115]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 13:13
Оценка:
Здравствуйте, σ, Вы писали:

σ>Правила есть разные, и последствия от их нарушения тоже разные. Какие-то нарушения делают программу ill-formed, какие-то — не делают.

σ>Короче. Чтобы долго воду в ступе не толочь (я знаю, ты любишь).

Спасибо, что повеселил. Дальше читать не вижу смысла.
--
Справедливость выше закона. А человечность выше справедливости.
Re[118]: Че ты лыбишься, хам трамвайный?
От: vopl Россия  
Дата: 23.08.23 13:14
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, vopl, Вы писали:


V>>Там дальше будут вопросы, лучше на них ответь.


R>А мне не нужно "дальше", мне достаточно того, что я уже увидел. Я вообще считаю, что если человек не способен сформулировать свою мысль одним четким копактным абзацем, то в голове у него путаница. И бродить по этим лабиринтам сознания у меня мотивации ноль.


это пять ящитаю
Re[119]: Че ты лыбишься, хам трамвайный?
От: rg45 СССР  
Дата: 23.08.23 13:15
Оценка:
Здравствуйте, vopl, Вы писали:

V>это пять ящитаю


Щитай
--
Справедливость выше закона. А человечность выше справедливости.
Re[112]: в холодной воде
От: B0FEE664  
Дата: 23.08.23 14:16
Оценка:
Здравствуйте, rg45, Вы писали:

σ>>Если программа constructed according to the syntax and semantic rules , а нарушение semantic rules, или ещё что-то подходящее под определение UB, возникнет во время её execution, то это никак не отменит well-formed

R>Если "возникнет", значит "not constructed according..." — все просто.

Если рассуждать формально, то неопределённое поведение при переполнении знакового целого — это следование правилу, а не нарушение правила. Нарушением правила бы было определённое поведение там, где должно быть неопределённое поведение.
И каждый день — без права на ошибку...
Re[113]: в холодной воде
От: rg45 СССР  
Дата: 23.08.23 14:19
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Если рассуждать формально, то неопределённое поведение при переполнении знакового целого — это следование правилу, а не нарушение правила. Нарушением правила бы было определённое поведение там, где должно быть неопределённое поведение.


Да понял я уже давно свою ошибку. Так, куражусь просто.

Характер скверный — предки виноваты

--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.08.2023 14:24 rg45 . Предыдущая версия .
Re[82]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 27.08.23 11:46
Оценка: +1
Здравствуйте, σ, Вы писали:

V>>Например:

V>>
σ>std::map<int, int> buildMap() {
σ>    std::map<int, int> result;

σ>    result.insert(42, 43); // мутабельность
σ>}

σ>const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект
σ>

σ>Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект. Он будет константным?

[cменяю мнение ]

В значительной мере вкурив это положение стандарта, лично я прихожу к выводу что на самом деле нет оснований полагать, что объект один.

In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


Мой перевод
В таких случаях, реализация трактует source и target в аспекте опущенной copy/move operation просто как два различных пути сослаться на один и тот же объект.

Моя трактовка
относительно опущенной copy/move operation
компилятор должен считать (имена/переменные) source и target
указывающими на один и тот же объект

То есть, "считать за один и тот же объект" — это только "в рамках выдавливания copy/move". Про любые другие аспекты речь не идет, следовательно, в них никакой не "один и тот же объект". Формально, декларация source и декларация target определяют два разных объекта, у каждого свой тип и все остальные свойства. И только лишь когда над ними производится выдавливание copy/move, то в рамках этого выдавливания "считаем что source и target указывают на один объект", не более.
Re[83]: Когда это наконец станет defined behavior?
От: rg45 СССР  
Дата: 27.08.23 11:58
Оценка: +1
Здравствуйте, vopl, Вы писали:

V>>>Например:

V>>>
σ>>std::map<int, int> buildMap() {
σ>>    std::map<int, int> result;

σ>>    result.insert(42, 43); // мутабельность
σ>>}

σ>>const std::map<int, int> xxx = buildMap(); // сохранили в иммутабельный объект
σ>>

σ>>Вопрос с подвохом: что если происходит NRVO и result с xxx обозначают один и тот же объект. Он будет константным?

V>[cменяю мнение ]


V>В значительной мере вкурив это положение стандарта, лично я прихожу к выводу что на самом деле нет оснований полагать, что объект один.

V>

In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object.


V>Мой перевод

V>В таких случаях, реализация трактует source и target в аспекте опущенной copy/move operation просто как два различных пути сослаться на один и тот же объект.

V>Моя трактовка

V>относительно опущенной copy/move operation
V>компилятор должен считать (имена/переменные) source и target
V>указывающими на один и тот же объект

V>То есть, "считать за один и тот же объект" — это только "в рамках выдавливания copy/move". Про любые другие аспекты речь не идет, следовательно, в них никакой не "один и тот же объект". Формально, декларация source и декларация target определяют два разных объекта, у каждого свой тип и все остальные свойства. И только лишь когда над ними производится выдавливание copy/move, то в рамках этого выдавливания "считаем что source и target указывают на один объект", не более.


Даже если допустить, что формулировка кривовата, отказываться от подобного использования, опасаясь UB, лично я не стал бы.
--
Справедливость выше закона. А человечность выше справедливости.
Re[16]: Когда это наконец станет defined behavior?
От: Sm0ke Россия ksi
Дата: 27.08.23 16:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>
R>int i;
R>const int& r = i;
R>r = 3;
R>


R>Ссылка на константный объект! А объект-то нифига не константный.


Ссылка на константный объект, которая проинициализирована не-кностантным lvalue.
Re[53]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 11:19
Оценка:
Здравствуйте, vdimas, Вы писали:

v> Ты намекаешь на отсутствие автоматического распространения константности по указателям и ссылкам?

Я ни на что не намекаю, просто ты теряешь контекст разговора. Моя реплика относится к "хеш-функцию пишется один раз". Нет, не пишется она один раз, т.к. в течение жизни проекта поля в объекте могут меняться и требовать модификаций этой функции.
Впрочем, в java завезли records, которые избавляют от этой необходимости.

v> Гарантии создаёт программист согласно требуемой семантике, разумеется.

v> Разумеется, и в джаве и в плюсах можно обеспечить все требуемые гарантии.
Зачем ты это мне всё рассказываешь? Я указал на ошибку в тезисе T4r4sB: "Как жаба следит чтоб ты не менял ключи хешмап? В С++ есть const. Этого достаточно.". Суть моего тезиса в том, что const не достаточно и в C++ ситуация такая же как и в java — гарантии обеспечивает таки программист.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[59]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 11:24
Оценка:
Здравствуйте, vdimas, Вы писали:

v> ·>Я это прекрасно знаю. Ровно то же и в java. Просто T4r4sB заявил
Автор: T4r4sB
Дата: 12.05.23
, что в C++ есть какая-то защита в виде const. Да не даёт const ровным счётом ничего.

v> Даёт экономию труда примерно вдвое в обсуждаемых сценариях.
Речь шла не про экономию труда, а про гарантии корректности и защиту, подменой тезиса ты занимаешься. Да и неясно в чём ты намерял экономию. Используя record в java можно наэкономить раз в десять в некоторых случаях.

v> ·>Только если либо копия передаётся, либо передача ownership, и это немного помогает в некоторых случаях, но возможностей стрельнуть в ногу всё равно дофига.

v> Возможностей стрельнуть себе в ногу дофига где угодно.
v> Тут рассуждения такие: меньше кода — меньше ошибок.
Спорное утверждение. Элементарно опровергаемое — прогнав прогу через обфускатор легко уменьшить количество кода, оставив число ошибок ровно таким же.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 28.08.2023 11:25 · . Предыдущая версия .
Re[58]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 11:31
Оценка:
Здравствуйте, vdimas, Вы писали:

v> reference_wrapper хранит ссылку как значение, т.е. придаёт ссылке св-ва указателя.

v> Соотв, когда будешь описывать операторы сравнения для reference_wrapper, сравнивать надо identity ссылаемых объектов, а не содержимое.
Искать в мапе, как правило, надо по содержимому.

v> В любом случае, пример твой некорректен согласно логике спора, бо ты пытаешься рассуждать об потенциальных ошибках обеспечения константности-иммутабельности, где ошибки можно допустить и в джаве (и где угодно) в попытках обеспечения этой иммутабельности.

Это твои фантазии. Перечитай.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[81]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 11:41
Оценка:
Здравствуйте, vdimas, Вы писали:


v> В шарпе для такого сценария есть отдельно иммутабельный аналог map, и отдельно мутабельный builder для него.

v> В С++ не потребовалось создавать две сущности.
Ровно те же две сущности тоже: "map" и "const map". Просто синтаксис чуток отличается.

v> Этот сценарий может возникнуть не только вокруг иммутабельного map, где в шарпе постелили соломку, а вообще везде.

Этот сценарий может возникнуть не только вокруг константности, а вообще везде. В C++ подстелили соломку, взяв легаси от C, а интерфейсы могут покрыть любую семантику. Например, "очередь в которую можно только добавлять, но ничего нельзя удалять" — вполне может оказаться полезным интерфейсом.

v> Собсно, только об этом и говорится в обсуждении (многократно по кругу) — что практически любой мутабельный тип можно использовать в т.ч. в иммутабельных сценариях.

Не любой, а тот для которого аккуратно задизайнен const-набор методов.

v> Остальные сценарии, когда мутабельный объект подаётся по константной ссылке — это просто удобные гарантии, т.к. после вызова метода с таким аргументом ты можешь в коде рассуждать о том, что целевой объект в результате вызова некоей ф-ии с им-аргументом, не изменился.

Ровно это же обеспечивается и соответсвующим интерфейсом.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[83]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 12:28
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Интерфейсы и в плюсах доступны.

В С++ с ними связаны накладные расходы.

V>И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.

Иммутабельность нельзя через view обеспечить. Ты тоже что-ли путаешь константность и иммутабельность?
Константность означает, что объект нельзя поменять. А иммутабельность, что объект не может поменяться.

V>Просто это слишком частый сценарий, поэтому органично включён в язык, дабы достигать того же самого без лишних приседаний.

Что считать приседаниями и стоят ли они такого значительного усложнения системы типов языка — вопрос очень спорный. Но я от этого спора уклонюсь.

V>·>А две сущности в C++ тоже есть, просто неявно. Вместо явного интерфейса делается пара const- и просто-методов.

V>Так мы только выразительность языков и обсуждаем.
Обсуждение началось с вопроса о том, что константность вещь очень важная и нужная и в других ЯП без неё всё плохо. Мой тезис в том, что это вовсе не так, и множество других ЯП прекрасно обходятся без константности.

V>·>Константные объекты появляются не магически, а в определениях соответствующих полей и методов.

V>И в правилах языка, где константные методы можно вызывать у неконстантного объекта, а наоборот нет.
В шарпах-явах то же самое выражается в виде системы типов с интерфейсами и наследованием.

V>Например, св-во size() (count, amount и т.д.) определены как const, соответственно, описаны однажды для константного и неконстантного объекта.

V>И всё это продолжает работать в таких сценариях:
V>logCollection(cl); // отдали куда-то по константной ссылке
Насчёт выразительности — читая этот код — здесь это никак не выражено. И никак не проверяется компилятором. Завтра вася поменяет определение logCollection, потеряет или сломает константность — и приехали.

V>for(size_t i = 0; i < size; i++) // незачем запрашивать размер коллекции заново

Ну это удобство для компилятора, а не для человека. В яве с этим мучается обычно JIT.

V>·>И там и там надо вводить два типа. Ведь T и const T это тоже разные типы.

V>Да.
V>Но описание типа программистом — одно.
В каком смысле "одно"? Можно описать в соседних строчках файла? Или что? Чем описание интерфейса "другее"?

V>Т.е., итераторы на интерфейсах сделаны не только потому что невозможно было накрутить логику как в плюсах через begin/end (в нынешнем шарпе уже можно сделать достаточно близко к плюсовомоу подходу, получив дешевизну), но еще потому что ДРУГОЙ интерфейс обеспечивает ДРУГУЮ семантику. В данном случае IEnumerator — это read-only семантика, т.е. употребима к мутабельным и немутабельным типам. В итоге для каждой коллекции приходится описывать еще и енумератор.

V>А вот если речь должна идти про сами типы-коллекции, то появляются пары Span/ReadOnlySpan, Memory/ReadOnlyMemory и т.д.
И что в этом плохого-то? Чем таким принципиально важным "const Span" отличается от "ReadOnlySpan"?

V>И это еще в шарпе по-лёгкoму, т.к. язык позволяет определять операторы преобразования, поэтому смогли определить неявное конструирование ReadOnly-версий из мутабельных.

V>В джаве пришлось бы делать двойную работу, окучивая каждую пару.
Ну в джаве в похожем месте другой дизайн — там буферы, readonly означает, что можно читать данные (при этом сам буфер как объект меняется — сдвигается position и т.п.), но записывать данные нельзя. Что-то похожее на memory mapped file, открытый с ro-правами.

V>>>Остальные сценарии, когда мутабельный объект подаётся по константной ссылке — это просто удобные гарантии, т.к. после вызова метода с таким аргументом ты можешь в коде рассуждать о том, что целевой объект в результате вызова некоей ф-ии с им-аргументом, не изменился.

V>·>Аналог final.
V>Не, final-метод в джаве обозначает другое.
final-поле и final-переменная я имею в виду.

V>·>Суть моего тезиса в том, что семантика const в других ЯП выражается тоже, просто через другие механизмы языка.

V>Суть в том, что иммутабельность — такой же "трюк", облегчающий программистам жизнь, как и куча других.
Разговор о том, насколько этот трюк необходим, начался разговор с того, что "как же в других ЯП без него обходятся", я рассказал как.

V>И тут С++ задолго до, как грится, оказался к этому готов. ))

V>А вот почему более поздние джава и шарп оказались не готовы — вопрос вопросов, однако.
В java есть record, давно уже готово.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[84]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 28.08.23 16:48
Оценка:
Здравствуйте, ·, Вы писали:

V>>И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.

·>Иммутабельность нельзя через view обеспечить.

Обеспечить-то программным образом можно, ес-но.
Нельзя обеспечить, скажем, контроль иммутабельности со стороны компилятора, т.е. нельзя задать гарантии через ср-ва языка.


·>Ты тоже что-ли путаешь константность и иммутабельность?


Применительно к данным — это одно и то же.
Применительно к ссылкам/указателям на данные — необходимо уточнять, что имеется ввиду — константность указателя или самих данных.

Константность можно добавлять неиммутабельным данным по ссылке/указателю, убирать константность нельзя.
То бишь, для любых константных данных их иммутабельность автоматически гарантируется.

Код, принимающий аргументы по константной ссылке или указателю, может быть одинаков для иммутабельных и неиммутабельных объектов (в части их const-интерфейса) — как прямое следствие возможности добавления к типу модификатора const по указателю/ссылке.


·>Константность означает, что объект нельзя поменять. А иммутабельность, что объект не может поменяться.


ха-ха
Это в тебе говорит прокуренность джавой, где ты вместо переменной ссылочного типа видишь сам объект за ним.

В плюсах такая константность раздается независимо как переменной-указателю, так и указуемым данным:
const SomeObj * const obj = getObj();

Переменная obj является иммутабельной, инициализирована указателем на объект типа const SomeObj.


V>>Просто это слишком частый сценарий, поэтому органично включён в язык, дабы достигать того же самого без лишних приседаний.

·>Что считать приседаниями и стоят ли они такого значительного усложнения системы типов языка — вопрос очень спорный.

Насчёт "значительно" перебор, ИМХО, бо правила вокруг const просты, даже слишком.


·>Но я от этого спора уклонюсь.


Потому что спор бесполезный.
Сравнивалась выразительность языков, где бесполезно сравнивать декларативные пометки внутри одного класса с описанием доп. классов (разделение на builder и immutable-версии одной и той же структуры данных).


V>>Так мы только выразительность языков и обсуждаем.

·>Обсуждение началось с вопроса о том, что константность вещь очень важная и нужная и в других ЯП без неё всё плохо.

Больше работы — плохо.
Это и есть "выразительность".


·>Мой тезис в том, что это вовсе не так, и множество других ЯП прекрасно обходятся без константности.


1. Обходятся за счёт лишнего труда программиста.
2. Присутствует принципиальная сложность обеспечить константность для ссылочных типов, иначе это было бы давно сделано.

Спроси меня "почему?" — растолкую подробно, почему в C# аналог const есть только для структур, но не может быть применён к классам.
Это не в недостатке машинки дотнета дело, а в семантике ссылочно-ориентированных языков.

Повторюсь:

·>Ты ... путаешь константность и иммутабельность?
Применительно к данным — это одно и то же.



V>>·>Константные объекты появляются не магически, а в определениях соответствующих полей и методов.

V>>И в правилах языка, где константные методы можно вызывать у неконстантного объекта, а наоборот нет.
·>В шарпах-явах то же самое выражается в виде системы типов с интерфейсами и наследованием.

Но компилятор умывает руки, бо это контракты прикладного уровня, которые легко нарушить.
Плюсовые контракты нарушить сложнее во много раз.
(разве что через реинтерпретацию/хак памяти, но аналогичные ср-ва есть и в дотнете, и в джаве, вроде)


·>Насчёт выразительности — читая этот код — здесь это никак не выражено. И никак не проверяется компилятором. Завтра вася поменяет определение logCollection, потеряет или сломает константность — и приехали.


Сломает через хак, если.
А законными ср-вами сложно.


V>>for(size_t i = 0; i < size; i++) // незачем запрашивать размер коллекции заново

·>Ну это удобство для компилятора, а не для человека. В яве с этим мучается обычно JIT.

JIT и компиляторы не всесильны, они хорошо работают только в простейших случаях (где никакого const и не надо, бо компилятор и без сопливых видит жизиненный цикл данных).
Обсуждаемое помогает именно там, где никакой JIT и компилятор уже не справляются.


V>>·>И там и там надо вводить два типа. Ведь T и const T это тоже разные типы.

V>>Да.
V>>Но описание типа программистом — одно.
·>В каком смысле "одно"? Можно описать в соседних строчках файла? Или что? Чем описание интерфейса "другее"?

Тем, что по интерфейсу не гарантируется иммутабельность — компилятор умывает руки.
А если в плюсах создал const-объект, то он достоверно иммутабельный (с точностью до замечания о распространении константности по ссылочным полям, где решение я давал).


V>>А вот если речь должна идти про сами типы-коллекции, то появляются пары Span/ReadOnlySpan, Memory/ReadOnlyMemory и т.д.

·>И что в этом плохого-то? Чем таким принципиально важным "const Span" отличается от "ReadOnlySpan"?

Тем, что достаточно было одного типа Span, некоторые св-ва и методы которого помечены как const (и эти методы и св-ва уже и так присутствуют, просто без пометки).


V>>И это еще в шарпе по-лёгкoму, т.к. язык позволяет определять операторы преобразования, поэтому смогли определить неявное конструирование ReadOnly-версий из мутабельных.

V>>В джаве пришлось бы делать двойную работу, окучивая каждую пару.
·>Ну в джаве в похожем месте другой дизайн — там буферы, readonly означает, что можно читать данные (при этом сам буфер как объект меняется — сдвигается position и т.п.), но записывать данные нельзя. Что-то похожее на memory mapped file, открытый с ro-правами.

В этом случае достаточен readonly итератор, т.е. некий view над иммутабельными данными.


V>>Не, final-метод в джаве обозначает другое.

·>final-поле и final-переменная я имею в виду.

Бгг, что намекает о том, что пользовательских value-типов в джаве никогда не будет. ))
Ведь в шарпе повторили семантику const для них, где соотв. методы помечены как readonly, т.е. другое ключевое слово (аналог final-классов и final-методов в шарпе sealed).


V>>Суть в том, что иммутабельность — такой же "трюк", облегчающий программистам жизнь, как и куча других.

·>Разговор о том, насколько этот трюк необходим, начался разговор с того, что "как же в других ЯП без него обходятся", я рассказал как.

И малость засверкал наивностью, бо все и так прекрасно в курсе, как обходятся в других ЯП.
А ты стал лишь подтверждать исходные тезисы. ))

(Вряд ли для плюсовкиа его язык единственный или хотя бы первый, для нашего поколения он шёл обычно вторым-третьим языком, т.е. на плюсы подсаживались обычно более чем сознательно).


V>>А вот почему более поздние джава и шарп оказались не готовы — вопрос вопросов, однако.

·>В java есть record, давно уже готово.

Ну какой давно, пару лет еще не прошло.
В котлине дата-классы давнее.
И это закрывается только малая часть сценариев вокруг иммутабельности.
Re[85]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 28.08.23 19:33
Оценка: :)
Здравствуйте, vdimas, Вы писали:

V>>>И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.

V>·>Иммутабельность нельзя через view обеспечить.
V>Обеспечить-то программным образом можно, ес-но.
Нет, нельзя. Ты не можешь сделать иммутабельный view к мутабельному объекту. Вообще никак, это просто бессмысленно. Можно сделать read-only view, но не иммутабельный view.

V>Нельзя обеспечить, скажем, контроль иммутабельности со стороны компилятора, т.е. нельзя задать гарантии через ср-ва языка.

Можно создать иммутабельный объект копируя мутабельные данные, ну или через передачу владения, собственно всё. Ну или если у тебя какой-нибудь rust с borrow checker.

V>·>Ты тоже что-ли путаешь константность и иммутабельность?

V>Применительно к данным — это одно и то же.
V>Применительно к ссылкам/указателям на данные — необходимо уточнять, что имеется ввиду — константность указателя или самих данных.
Указатель — это тоже вид данных, не надо мудрствовать.

V>Константность можно добавлять неиммутабельным данным по ссылке/указателю, убирать константность нельзя.

V>То бишь, для любых константных данных их иммутабельность автоматически гарантируется.
Иммутабельность гарантируется только тогда, когда к данным нет легального способа получить мутабельный доступ.

V>Код, принимающий аргументы по константной ссылке или указателю, может быть одинаков для иммутабельных и неиммутабельных объектов (в части их const-интерфейса) — как прямое следствие возможности добавления к типу модификатора const по указателю/ссылке.

Это не достаточное условие. У типа должны быть какие-то определённые const-методы (или, другими словами, const-интерфейс). Иначе наличие такой ссылки тебе ничего не даст, т.к. не сможешь ничего сделать. В чём разница с интерфейсами — неясно.

V>·>Константность означает, что объект нельзя поменять. А иммутабельность, что объект не может поменяться.

V>ха-ха
V>Это в тебе говорит прокуренность джавой, где ты вместо переменной ссылочного типа видишь сам объект за ним.
Ерунда какая-то. В точности наоборот, в джаве все объекты — только по ссылке.

V>В плюсах такая константность раздается независимо как переменной-указателю, так и указуемым данным:

V>
V>const SomeObj * const obj = getObj();
V>

V>Переменная obj является иммутабельной, инициализирована указателем на
ну в случае final SomeObj obj = getObj() в яве тоже, переменная тоже "иммутабельная". Правда толку маловато будет. Применять термин Иммутабельность к переменной — как-то бессмысленно, только для разведения демагогии годится. Мутабельность-иммутабельность обычно относится к состоянию объекта.

V> объект типа const SomeObj.

Ага. А вот тут уже интереснее — именно что const-объекта, но про иммутабельность — ичсх ты промолчал. Демагогия, ЧТД.

V> Насчёт "значительно" перебор, ИМХО, бо правила вокруг const просты, даже слишком.

Только что тут флейм был на сотню сообщений что где когда с константностью происходит. Ага, ага, всё просто.

V>·>Но я от этого спора уклонюсь.

V>Потому что спор бесполезный.
Потому что бесмысленный, основанный на субъективщине и вкусовщине.

V>Сравнивалась выразительность языков, где бесполезно сравнивать декларативные пометки внутри одного класса с описанием доп. классов (разделение на builder и immutable-версии одной и той же структуры данных).

Если ты таки поймёшь разницу между константностью и иммутабельностью, то поймёшь, что в плюсах ситуация ровно такая же.

V>>>Так мы только выразительность языков и обсуждаем.

V>·>Обсуждение началось с вопроса о том, что константность вещь очень важная и нужная и в других ЯП без неё всё плохо.
V>Больше работы — плохо.
А в чём работу меряешь-то? Пишешь record, вешаешь @Builder аннотацию и готово. Да даже без этого, с современной IDE работу делает железяка, а не программист.

V>·>Мой тезис в том, что это вовсе не так, и множество других ЯП прекрасно обходятся без константности.

V>1. Обходятся за счёт лишнего труда программиста.
Этот труд давно автоматизирован и поэтому не программист трудится.

V>2. Присутствует принципиальная сложность обеспечить константность для ссылочных типов, иначе это было бы давно сделано.

V>Спроси меня "почему?" — растолкую подробно, почему в C# аналог const есть только для структур, но не может быть применён к классам.
Потому что они статик? Имхо, просто ошибка в проектировании семантики языка.

V>Это не в недостатке машинки дотнета дело, а в семантике ссылочно-ориентированных языков.

Ну в общем-да. Но ты говоришь, как будто это что-то плохое, называешь недостатком.

V>·>Ты ... путаешь константность и иммутабельность?

V>Применительно к данным — это одно и то же.
В этом случае есть final в джава. Но это неинтересный случай, а демагогия.

V>>>И в правилах языка, где константные методы можно вызывать у неконстантного объекта, а наоборот нет.

V>·>В шарпах-явах то же самое выражается в виде системы типов с интерфейсами и наследованием.
V>Но компилятор умывает руки, бо это контракты прикладного уровня, которые легко нарушить.
V>Плюсовые контракты нарушить сложнее во много раз.
V>(разве что через реинтерпретацию/хак памяти, но аналогичные ср-ва есть и в дотнете, и в джаве, вроде)
В целом да, цена универсальности. Зашивать конкретный контракт в спеку ЯП — очень тяжелая артиллерия. Имхо, в данном случае, неоправданная. Но это _имхо_. Спорить не буду.

V>·>Насчёт выразительности — читая этот код — здесь это никак не выражено. И никак не проверяется компилятором. Завтра вася поменяет определение logCollection, потеряет или сломает константность — и приехали.

V>Сломает через хак, если.
V>А законными ср-вами сложно.
Какой хак? Было logCollection(const X&), потом вдруг немного что-то понадобилось где-то и поменял на logCollection(X&), а код всё ещё компиляется как ни в чём не бывало. А в плюсах ошибка в размере типично ведёт к UB и оно даже может как-то работать.

V>>>for(size_t i = 0; i < size; i++) // незачем запрашивать размер коллекции заново

V>·>Ну это удобство для компилятора, а не для человека. В яве с этим мучается обычно JIT.
V>JIT и компиляторы не всесильны, они хорошо работают только в простейших случаях (где никакого const и не надо, бо компилятор и без сопливых видит жизиненный цикл данных).
V>Обсуждаемое помогает именно там, где никакой JIT и компилятор уже не справляются.
Ну идея JIT в том, что таких простейших случаев 99.9%, а там где оно не справилось, там попрофилируем и пооптимизируем вручную.

V>·>В каком смысле "одно"? Можно описать в соседних строчках файла? Или что? Чем описание интерфейса "другее"?

V>Тем, что по интерфейсу не гарантируется иммутабельность — компилятор умывает руки.
Иммутабельность (не путай с константностью) и в плюсах ничем не может гарантироваться. Ты сам вроде это мне доказывал. А аналог const есть и в java в виде final.

V>А если в плюсах создал const-объект, то он достоверно иммутабельный (с точностью до замечания о распространении константности по ссылочным полям, где решение я давал).

А как ты достоверно создашь const-объект-то? Ну тот же std::map, например? В лучшем случае через defensive copy или через передачу владения. Ровно так же как и в шарпах-явах.

V>>>А вот если речь должна идти про сами типы-коллекции, то появляются пары Span/ReadOnlySpan, Memory/ReadOnlyMemory и т.д.

V>·>И что в этом плохого-то? Чем таким принципиально важным "const Span" отличается от "ReadOnlySpan"?
V>Тем, что достаточно было одного типа Span, некоторые св-ва и методы которого помечены как const (и эти методы и св-ва уже и так присутствуют, просто без пометки).
Я имею в виду с т.з. программиста? Реальная причина в том, что им приходится Span делать как struct и избегать боксинга, т.е. просто реализовать ифейс они не не могут. Проблема в компиляторе, в оптимизации, а не в выразительности для человека.

V>>>И это еще в шарпе по-лёгкoму, т.к. язык позволяет определять операторы преобразования, поэтому смогли определить неявное конструирование ReadOnly-версий из мутабельных.

V>>>В джаве пришлось бы делать двойную работу, окучивая каждую пару.
V>·>Ну в джаве в похожем месте другой дизайн — там буферы, readonly означает, что можно читать данные (при этом сам буфер как объект меняется — сдвигается position и т.п.), но записывать данные нельзя. Что-то похожее на memory mapped file, открытый с ro-правами.
V>В этом случае достаточен readonly итератор, т.е. некий view над иммутабельными данными.
Ну там довольно сложный набор методов — взятие данных различных размеров, по разным позициям и т.п. По сути итератор и есть, но очень навороченный, заточенный для обработки бинарных блоков.

V>>>Не, final-метод в джаве обозначает другое.

V>·>final-поле и final-переменная я имею в виду.
V>Бгг, что намекает о том, что пользовательских value-типов в джаве никогда не будет. ))
Ну вроде Valhalla пилят, правда с низким приоритетом...

V>Ведь в шарпе повторили семантику const для них, где соотв. методы помечены как readonly, т.е. другое ключевое слово (аналог final-классов и final-методов в шарпе sealed).

Не понял что к чему.

V>>>Суть в том, что иммутабельность — такой же "трюк", облегчающий программистам жизнь, как и куча других.

V>·>Разговор о том, насколько этот трюк необходим, начался разговор с того, что "как же в других ЯП без него обходятся", я рассказал как.
V>И малость засверкал наивностью, бо все и так прекрасно в курсе, как обходятся в других ЯП.
V>А ты стал лишь подтверждать исходные тезисы. ))
V>(Вряд ли для плюсовкиа его язык единственный или хотя бы первый, для нашего поколения он шёл обычно вторым-третьим языком, т.е. на плюсы подсаживались обычно более чем сознательно).
Судя по обсуждению — далеко не все в курсе.

V>>>А вот почему более поздние джава и шарп оказались не готовы — вопрос вопросов, однако.

V>·>В java есть record, давно уже готово.
V>Ну какой давно, пару лет еще не прошло.
До этого — lombok если очень хотелось.

V>В котлине дата-классы давнее.

И в scala case-классы ещё давнее.

V>И это закрывается только малая часть сценариев вокруг иммутабельности.

А что не закрывается?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 28.08.2023 21:54 · . Предыдущая версия .
Re[13]: Почему?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 31.08.23 06:20
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>CLANG

S>
S>f1():                                 # @f1()
S>        xorl    %eax, %eax
S>        retq
S>


S>p/s: это при -O2


S>Почему?


x в f1 неинициализирован. Оптимизация в одной функции это видит быстрее, чем в двух разделённых. Неициализировано => в LLVM есть специальная отработка undef и poison значений, которая по сути сводится к "выбирай что больше нравится, всё одно там фигня".
В принципе компилятор мог и вообще убрать запись чего-то в eax, но вот решил оставить.
The God is real, unless declared integer.
Re[14]: Почему?
От: Sm0ke Россия ksi
Дата: 31.08.23 16:27
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Sm0ke, Вы писали:


S>>CLANG

S>>
S>>f1():                                 # @f1()
S>>        xorl    %eax, %eax
S>>        retq
S>>


S>>p/s: это при -O2


S>>Почему?


N>x в f1 неинициализирован. Оптимизация в одной функции это видит быстрее, чем в двух разделённых. Неициализировано => в LLVM есть специальная отработка undef и poison значений, которая по сути сводится к "выбирай что больше нравится, всё одно там фигня".

N>В принципе компилятор мог и вообще убрать запись чего-то в eax, но вот решил оставить.

Тип переменной известен на этапе компиляции как bool.
Исходя из логики выражение { bool x; return x||!x; } должно возвращать всегда true, независимо от значения x. И при значении x = true, и при значении x = false.
Операторы для bool не перегружены пользователем, ответ однозначен. Как оптимизатор будет это осуществлять: методом перебора, или уметь упрощать логические выражения — не так важно.

Если оптимизатор не может некий случай упростить с корректным результатом, то лучше пусть не упрощает.
Даже если стандарт позволяет при чтении неинициализированной переменной (UB) лепить компилятору что угодно.


Ещё пример:
#include <iostream>

int f1(int p) { int x; return p + x * 0; }

int f2(int p) { int x; return p + (x - x); }

int main()
{
  std::cout << f1(5) << '\n';
  std::cout << f2(5) << '\n';
  return 0;
}

Тут оптимизатор справляется
Re[86]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 31.08.23 18:05
Оценка:
Здравствуйте, ·, Вы писали:

V>>>>И прочие GOF-трюки, где иммутабельность может быть св-вом объекта, а может быть адаптером-view.

V>>·>Иммутабельность нельзя через view обеспечить.
V>>Обеспечить-то программным образом можно, ес-но.
·>Нет, нельзя. Ты не можешь сделать иммутабельный view к мутабельному объекту. Вообще никак, это просто бессмысленно. Можно сделать read-only view, но не иммутабельный view.

Заканчивай уже употреблять слова, смысла которых не понимаешь. ))
Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность.


V>>Нельзя обеспечить, скажем, контроль иммутабельности со стороны компилятора, т.е. нельзя задать гарантии через ср-ва языка.

·>Можно создать иммутабельный объект копируя мутабельные данные

Или литералы-константы, или другие иммутабельные объекты.


·>ну или через передачу владения, собственно всё.


Ес-но.
Об этом и речь, что иммутабельность целиком переезжает на прикладной уровень в джаве, а компилятор умывает руки.
Стоило ли ради этого столько постов трепыхаться? ))


V>>·>Ты тоже что-ли путаешь константность и иммутабельность?

V>>Применительно к данным — это одно и то же.
V>>Применительно к ссылкам/указателям на данные — необходимо уточнять, что имеется ввиду — константность указателя или самих данных.
·>Указатель — это тоже вид данных, не надо мудрствовать.

Именно, как и ссылочная переменная в джаве.
А ты лишь опять сотрясал воздух без понимания определений. ))


V>>Константность можно добавлять неиммутабельным данным по ссылке/указателю, убирать константность нельзя.

V>>То бишь, для любых константных данных их иммутабельность автоматически гарантируется.
·>Иммутабельность гарантируется только тогда, когда к данным нет легального способа получить мутабельный доступ.

Молодец!
Иммутабельность — это иммутабельность!

А константа — это константа!
И для обычных даных это в точности равно иммутабельности.
А для ссылочных данных константность может быть как "приобретаемым позже" свойством, так и неотъемлимым, приобретаемым непосредственно после создания данных (объекта).
Ву а ля!

Я ХЗ где ты тут в 3-х соснах плутаешь. ))


V>>Код, принимающий аргументы по константной ссылке или указателю, может быть одинаков для иммутабельных и неиммутабельных объектов (в части их const-интерфейса) — как прямое следствие возможности добавления к типу модификатора const по указателю/ссылке.

·>Это не достаточное условие.

Это не условие, дурилки картонные, это св-ва инструментария!

Нет абсолютно никакой потребности обеспечивать иммутабельность типа таком коде, достаточно гарантий, что этот код работает в т.ч. с иммутабельными данными.

Это банальное перепендикулярное разделение данных и кода!

Ладно, тут всё ясно.
Кажется, я понял причину твоих трудностей, что ты тут простыни кода исписал уже, ходишь по кругу. ))

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

Т.е. умудрился в упор не заметить, что иммутабельные и read-only сценарии существенно пересекаются (read-only сценарии являются строгим подмножеством иммутабельных сценариев).

Так вот, иммутабельность обеспечивается на уровне данных и более никак.
А код пишется как read-only или нет.
И на выходе у нас комбинаторика сценариев, а не сумма их.
Отредактировано 31.08.2023 18:06 vdimas . Предыдущая версия . Еще …
Отредактировано 31.08.2023 18:05 vdimas . Предыдущая версия .
Re[87]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 31.08.23 19:10
Оценка:
Здравствуйте, vdimas, Вы писали:

v> V>>·>Иммутабельность нельзя через view обеспечить.

v> V>>Обеспечить-то программным образом можно, ес-но.
v> ·>Нет, нельзя. Ты не можешь сделать иммутабельный view к мутабельному объекту. Вообще никак, это просто бессмысленно. Можно сделать read-only view, но не иммутабельный view.
v> Заканчивай уже употреблять слова, смысла которых не понимаешь. ))
А ты заканчивай коньяк по утрам пить и таки покажи пример кода как обеспечить иммутабельность через view мутабельного объекта.

v> Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность.

Это я и написал ниже.
Вопрос в том, как же компилятор проверяет/помогает гарантировать отстуствие протечек с помощью const? Ответ — да никак. Вывод — const бесполезен для иммутабельности.

v> ·>Можно создать иммутабельный объект копируя мутабельные данные

v> Или литералы-константы, или другие иммутабельные объекты.
Не понял твоё дополнение. Ты предлагаешь копировать литералы-константы, или другие иммутабельные объекты? Зачем? Важное свойство иммутабельных объектов в том, что их копии никак не отличимы от оригинала и копирование можно избегать.

v> ·>ну или через передачу владения, собственно всё.

v> Ес-но.
v> Об этом и речь, что иммутабельность целиком переезжает на прикладной уровень в джаве, а компилятор умывает руки.
Как и в Плюсах.

v> ·>Указатель — это тоже вид данных, не надо мудрствовать.

v> Именно, как и ссылочная переменная в джаве.
v> А ты лишь опять сотрясал воздух без понимания определений. ))
Ты сотрясал воздух отвечая на вопросы, которые никто не задавал.

v> V>>То бишь, для любых константных данных их иммутабельность автоматически гарантируется.

v> ·>Иммутабельность гарантируется только тогда, когда к данным нет легального способа получить мутабельный доступ.
v> Молодец!
v> Иммутабельность — это иммутабельность!
v> А константа — это константа!
Ровно твои слова же: "Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность". К чему сарказм-то?

Вопрос в том, как собственно обеспечить отсутствие протечек. И где что там у тебя автоматически гарантируется-то с помощью const?
Допустим, у тебя есть где-то const SomeThing someValue(42); — ты гарантируешь, что someValue — иммутабельно?

v> И для обычных даных это в точности равно иммутабельности.

Повторюсь. Данные — не объекты (если я правильно понял, что ты подразумеваешь под данными). Мы говорим об объектах.

v> А для ссылочных данных константность может быть как "приобретаемым позже" свойством, так и неотъемлимым, приобретаемым непосредственно после создания данных (объекта).

v> Ву а ля!
Приобретаемым как? Только заботой программиста. Компайлер c const ничего гарантировать не может.
В java record — гарантии есть, кстати.

v> Я ХЗ где ты тут в 3-х соснах плутаешь. ))

Ты вообще в двух соснах запутался. Да, каждый иммутабельный объект — константный, но это скучно. Важно то, что не каждый константный объект — иммутабельный. Следовательно константность никак не гарантирует иммутабельности. Это ложится на программиста, что в плюсах, что в джаве, что в шарпах. const для иммутабельности не нужен. Нужен record.

v> ·>Это не достаточное условие.

v> Это не условие, дурилки картонные, это св-ва инструментария!
v> Нет абсолютно никакой потребности обеспечивать иммутабельность типа таком коде, достаточно гарантий, что этот код работает в т.ч. с иммутабельными данными.
Так откуда ты берёшь эти гарантии-то? Рассказывай уже, не томи.

v> Ты зачем-то рассматривал данные и обрабатывающий его код как нечто неразрывное, верно?

Иммутабельность она и в африке иммутабельность.

v> Т.е. умудрился в упор не заметить, что иммутабельные и read-only сценарии существенно пересекаются (read-only сценарии являются строгим подмножеством иммутабельных сценариев).

Нет, не подмножеством. read-only view для мутабельного объекта — не подмножество иммутабельного сценария, ну никак.

v> Так вот, иммутабельность обеспечивается на уровне данных и более никак.

v> А код пишется как read-only или нет.
v> И на выходе у нас комбинаторика сценариев, а не сумма их.
Осталось понять ценность этого комбинаторного усложнения на ровном месте, это и есть основная тема этого обсуждения. Мой тезис в том, что иммутабельность — нужна и важна, константность — не является необходимостью и можно нафиг выкинуть, что собственно и сделали в шарпах-явах. Тогда нафиг никакой комбинаторики и всё просто.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[88]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 01.09.23 23:27
Оценка:
Здравствуйте, ·, Вы писали:

v>>Заканчивай уже употреблять слова, смысла которых не понимаешь. ))

·>А ты заканчивай коньяк по утрам пить

Без обид, но упор на жонглирование терминами всегда попахивает эзотерикой, эдакой попыткой наделить известные вещи некими новыми характеристиками, которые "собеседник наверняка недопонимает" (С).


·>покажи пример кода как обеспечить иммутабельность через view мутабельного объекта.


Легко — достаточно обеспечить отсутствие протекание ссылки на мутабельный объект.
(например, создавать приватный мутабельный объект в конструкторе view)


·>Вопрос в том, как же компилятор проверяет/помогает гарантировать отстуствие протечек с помощью const?


Достаточно просто — объявляешь данные как const и они автоматом становятся иммутабельными.

Иммутабельность автоматически распространяется при владении другими объектами по-значению.
При владении по указателю/ссылкам я давал хелпер для автоматического распространения иммутабельности.


·>Ответ — да никак.


Для этого необходимо показать хотя бы минимальный пример этого "никак".


·>Вывод — const бесполезен для иммутабельности.


Вывод — ты споришь о том, что недостаточно изучил, походу.


·>Важное свойство иммутабельных объектов в том, что их копии никак не отличимы от оригинала и копирование можно избегать.


Это лишь один из трюков, достижимых при иммутабельности.
Так же как шаренье иммутабельных данных без блокировки м/у потоками.

Но иммутабельные данные необходимо как-то создавать.
И наиболее эффективно их создавать в мутабельной манере.
Я уже отсылал к паттерну mutable_builder => immutable_object.

Вот после создания иммутабельного объекта, все эти трюки можно использовать.


v>> ·>ну или через передачу владения, собственно всё.

v>> Ес-но.
v>> Об этом и речь, что иммутабельность целиком переезжает на прикладной уровень в джаве, а компилятор умывает руки.
·>Как и в Плюсах.

В плюсах компилятор больно бъёт тебе по пальцам.
Собсно, новички в плюсах зачастую маются с компиллированием программ именно из-за попыток нарушения константности.


·>Ровно твои слова же: "Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность". К чему сарказм-то?


К тому, что компилятор в плюсах отслеживает попытки "протечек" и отказывается компилировать такой код.


·>Вопрос в том, как собственно обеспечить отсутствие протечек.


#include <iostream>
#include <unordered_map>

using namespace std;

// ключ
struct index {
  int a;
  int b;

  index(int a, int b) : a(a), b(b) {}

  bool operator==(const index &) const = default;
};

// хеш-функция для ключа
template<> struct std::hash<index> {
  size_t operator()(const index & i) const {
    hash<int> h;
    return h(i.a) ^ h(i.b) << 1;
  }
};

// хеш-таблица
typedef unordered_map<index, string> SomeDictionary;

// фабрика оперирует мутабельным объектом
SomeDictionary buildDictionary() {
  SomeDictionary result;

  result[{42, 43}] = "42, 43";
  result[{44, 45}] = "44, 45";

  return result;    
}

// но здесь иммутабельный объект
const SomeDictionary dict = buildDictionary();

int main()
{
  cout << dict.at({42, 43}) << endl;
  return 0;
}

Параметром шаблона хеш-таблицы выступает тип index, но в качестве ключа хеш-таблицы используется const index.
Такова спецификация, см. value_type тут:
https://en.cppreference.com/w/cpp/container/unordered_map


·>И где что там у тебя автоматически гарантируется-то с помощью const?


В данном примере гарантируется, что переменная dict иммутабельная, хотя на этапе построения мы пошагово мутировали значение.
Но даже в процессе мутации ключи таблицы были гарантированно иммутабельны.


·>Допустим, у тебя есть где-то const SomeThing someValue(42); — ты гарантируешь, что someValue — иммутабельно?


Без хаков если, то да.


v>> И для обычных даных это в точности равно иммутабельности.

·>Повторюсь. Данные — не объекты (если я правильно понял, что ты подразумеваешь под данными). Мы говорим об объектах.

Ты опять разбрасываешься терминами.

Объект — это не только термин из ООП-парадигмы. В плюсах объектами является всё, даже простой int.

Данные/значения — это термин из механики происходящего, где by ref или by value имеют однозначную интерпретацию.

Соотв., экземпляры одного и того же типа могут храниться как "просто данные", т.е. по значению, или могут быть ссылаемы через ссылку/указатель.


v>> А для ссылочных данных константность может быть как "приобретаемым позже" свойством, так и неотъемлимым, приобретаемым непосредственно после создания данных (объекта).

v>> Ву а ля!
·>Приобретаемым как? Только заботой программиста. Компайлер c const ничего гарантировать не может.

Например, так:
const SomeObject * obj = new SomeObject();

Здесь оператор new возвращает указатель на неконстантный объект, но мы его сохраняем в указатель на константный объект.
Если конструктор SomeObject не имеет побочных эффектов (не сохраняет указатель на себя где-нить в глобальной переменной, т.е. если нет протечек), то гарантии получаются железобетонные.

Примечание, сам указатель не является иммутабельным, его можно перезаписать другим экземпляром const SomeObject *.
Для иммутабельности самого указателя перед ним надо написать еще один const.


·>В java record — гарантии есть, кстати.


Я ж не против, чтобы компилятор помогал программисту.
Это его прямая обязанность. ))

Да, в плюсах можно разрабатывать достоверно иммутабельные типы данных:
struct immutable_index {
    const int a;
    const int b;
};

но какой смысл объявлять еще один тип данных, если можно сделать так:
using immutable_index = const index;

автоматом унаследовав всю инфраструктуру вокруг исходного типа, например, вычисление хеш-функции.


·>Важно то, что не каждый константный объект — иммутабельный. Следовательно константность никак не гарантирует иммутабельности.


Опять напоминаю, что константностей несколько разных — константность по значению и по ссылке.
По значению — всегда иммутабельность.
По константной ссылке/указателю ты можешь ссылаться на мутабельные и иммутабельные объекты, делая код ортогональным для данных.


·>Это ложится на программиста, что в плюсах, что в джаве, что в шарпах. const для иммутабельности не нужен. Нужен record.


Это вам в джаве нужен, т.к. иммутабельность обеспечивается прикладной семантикой, где record — лишь синтаксический сахар для такой семантики.

Сравни с тем, что в примере выше index не является иммутабельным типом, т.е. может использоваться в мутабельных сценариях.
Но в типе SomeDictionary const index резко становится иммутабельным.


v>> Нет абсолютно никакой потребности обеспечивать иммутабельность типа таком коде, достаточно гарантий, что этот код работает в т.ч. с иммутабельными данными.

·>Так откуда ты берёшь эти гарантии-то? Рассказывай уже, не томи.

Показал выше и рассказал:
— константные данные (объекты, хранимые по-значению) всегда иммутабельны;
— ссылки на константные данные не гарантируют константность тех данных, они накладывают ограничения — позволяют использовать лишь иммутабельное АПИ объектов.


v>> Ты зачем-то рассматривал данные и обрабатывающий его код как нечто неразрывное, верно?

·>Иммутабельность она и в африке иммутабельность.

Да нет, в базе есть данные и алгоритмы над данными.
Определённым классом алгоритмов являются алгоритмы над неизменяемыми данными.

Как именно данные случаются неизменяемыми — да как угодно.
Можно и безо-всяких const, record, final и прочих приблуд, достаточно того, чтобы в момент работы таких алгоритмов данные никто не изменял.

Тут мы рассуждаем лишь о том, как защититься от случайного изменения невнимательным программистом данных, которые мы хотим рассматривать как иммутабельные.

В общем, подход плюсов оказался настолько удобным, что его перетянули и в C# (но только для value-типов) и даже в последние версии FreePascal.
Ранее в этих языках был доступен только подход джавы.


v>> Т.е. умудрился в упор не заметить, что иммутабельные и read-only сценарии существенно пересекаются (read-only сценарии являются строгим подмножеством иммутабельных сценариев).

·>Нет, не подмножеством. read-only view для мутабельного объекта — не подмножество иммутабельного сценария, ну никак.

Еще как подмножество.
В полном наборе иммутабельных сценариев CRUD отсуствует CUD в read-only сценариях. ))
(сосредоточься, плиз)


v>> И на выходе у нас комбинаторика сценариев, а не сумма их.

·>Осталось понять ценность этого комбинаторного усложнения на ровном месте

Наоборот, упрощение, бо комбинаторный подход позволяет упростить базу — меньше писать.
Одним и тем же кодом в плюсах ты можешь проходиться по мутабельному и иммутабельному дереву, например.
В джаве тебе пришлось бы делать два типа дерева и два кода для их обхода (или выкручиваться через интерфйесы, что утяжеляет/тормозит).


·>Мой тезис в том, что иммутабельность — нужна и важна


Допустим.
Хотя, так можно сказать о любом достаточно широком классе алгоритмов.


·>константность — не является необходимостью


Разумеется, константность не является необходимостью для иммутабельных сценариев.
Она лишь дико экономит труд програмиста и размер конечного бинаря, а так-то фигня полная.


·>и можно нафиг выкинуть, что собственно и сделали в шарпах-явах.


Наоборот, в шарпе вот относительно недавно добавили.
А потом опять добавили.
Ключевое слово чуть другое — readonly, но смысл и сценарии использования те же.


·>Тогда нафиг никакой комбинаторики и всё просто.


Сложнее, обычно.
Причём, гораздо.
Вплоть до того, что даже в иммутабельных сценариях в джаве редко кто заморачивается с внутренней гарантией этой иммутабельности.

В плюсах ведь доступен подход джавы, но это ж издевательство над психикой, поэтому никто так не делает.
Бо програмисты — народ ленивый. ))
Re[114]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 02.09.23 22:18
Оценка:
Здравствуйте, vopl, Вы писали:

V>по стандарту объект создается того типа который был при его декларации


Он и создаётся того типа. ))


V>а деклараций две, это явная коллизия, зря мы тут копья ломаем


const не меняет лейаут объекта, а лишь ограничивает допустимый АПИ этого объекта.

Т.е., я не вижу никакой коллизии если сначала создать лейаут объекта в памяти, а потом ограничить его АПИ согласно модификатора const.

Это как сослаться на неконстантный объект по константной ссылке.
Согласно твоим рассуждениям — как так???
Это мы на некий тип ссылаемся как будто на другой тип? Ай-ай-ай! ))


V>по моим данным, "const" это часть свойства "тип" объекта


Модификатор типа.


V>Настаиваю что по формулировкам стандарта — это один объект.


Убрали пару деструктор+конструктор в "физике" происходящего, но "в уме"-то не убираем! ))
Соответственно, согласно семантики можно считать, что старый объект умер, а на его месте родился новый, точно такой же.

Я ж предлагал уже удалить конструктор копирования для проверки семантики.


V>Чуствую что скоро будет иметь место какой нибудь дефект-репорт, типа "NRVO makes an object type collision ...blabla"


Ни в коем случае.
Иначе бы ты не мог ссылаться константными ссылками на неконстантные объекты, если бы в этом месте возникала коллизия.
Re[106]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 02.09.23 22:33
Оценка:
Здравствуйте, vopl, Вы писали:

V>>Для UB недостаточно декларации — с объектом надо что-то "делать", чтобы наблюдать "поведение", которое вы обещали "потенциально неопределённое".

V>Для UB достаточно выполнить эти условия:

Any attempt to modify a const object during its lifetime results in undefined behavior.

И эти условия выполнены.


Это не все условия, бо UB, согласно термина, рассматривает исключительно и только некое поведение в рантайм, которое не может быть специфицировано стандартом, т.е. разные компиляторы или разные данные могут вызывать разное (неопределённое) поведение.


V>>До возврата из ф-ии с объектом ничего сделать нельзя.

V>а это уже не важно

Тогда исчезает буква B из термина UB. ))
Re[106]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 02.09.23 22:37
Оценка:
Здравствуйте, vopl, Вы писали:

V>- объект будет один а не два (со всеми вытекающими)


С какими еще вытеающими?
Пример можно?
Re[89]: Когда это наконец станет defined behavior?
От: · Великобритания  
Дата: 02.09.23 22:59
Оценка:
Здравствуйте, vdimas, Вы писали:
v> ·>А ты заканчивай коньяк по утрам пить
v> Без обид, но упор на жонглирование терминами
Я терминами не жонглировал.

v> ·>покажи пример кода как обеспечить иммутабельность через view мутабельного объекта.

v> Легко — достаточно обеспечить отсутствие протекание ссылки на мутабельный объект.
v> (например, создавать приватный мутабельный объект в конструкторе view)
Не очень понял что ты имеешь в виду, продемонстрируй кодом.

v> ·>Вопрос в том, как же компилятор проверяет/помогает гарантировать отстуствие протечек с помощью const?

v> Достаточно просто — объявляешь данные как const и они автоматом становятся иммутабельными.
А дальше что? В лучшем случае ты их можешь такими сделать в пределах локальной переменной или поля класса. В другом скопе он уже теряет иммутабельность.

v> Иммутабельность автоматически распространяется при владении другими объектами по-значению.

По значению это и есть defensive copy.

v> ·>Ответ — да никак.

v> Для этого необходимо показать хотя бы минимальный пример этого "никак".
Пример чего? Пример кода, который никак не написать??!

v> ·>Важное свойство иммутабельных объектов в том, что их копии никак не отличимы от оригинала и копирование можно избегать.

v> Это лишь один из трюков, достижимых при иммутабельности.
v> Так же как шаренье иммутабельных данных без блокировки м/у потоками.
Угу. А константные объекты даже пошарить нельзя.

v> Но иммутабельные данные необходимо как-то создавать.

v> И наиболее эффективно их создавать в мутабельной манере.
v> Я уже отсылал к паттерну mutable_builder => immutable_object.
Да, но там создаётся иммутабельная копия из данных мутабельного билдера. Как и в шарпах всяческих.

v> Вот после создания иммутабельного объекта, все эти трюки можно использовать.

С иммутабельным можно. С константным — не всегда, только компилятор гарантии не даёт.

v> ·>Как и в Плюсах.

v> В плюсах компилятор больно бъёт тебе по пальцам.
Компилятор ничего про иммутабельность не знает, поэтому по пальцам бить тупо не может. Нет такого понятия в стандарте. ИЧСХ, ты это и так прекрасно понимаешь (когда, например, ты скромно "забыл" назвать объект типа const SomeObj иммутабельным). Я не понимаю зачем ты тут этот цирк устраиваешь?

v> Собсно, новички в плюсах зачастую маются с компиллированием программ именно из-за попыток нарушения константности.

Это, кстати, тоже минус. С интерфейсами же всё проще — есть метод, можно дёрнуть, нет метода — нельзя дёрнуть.

v> ·>Ровно твои слова же: "Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность". К чему сарказм-то?

v> К тому, что компилятор в плюсах отслеживает попытки "протечек" и отказывается компилировать такой код.
Не отслеживает. Сам же ниже пишешь, например, о сценарии утечки this из конструктора.

v> ·>Вопрос в том, как собственно обеспечить отсутствие протечек.

v> result[{42, 43}] = "42, 43";
Здесь формально копиктор struct срабатывает.

v> // но здесь иммутабельный объект

v> const SomeDictionary dict = buildDictionary();
И здесь формально копия.

Но допустим у тебя есть этот самый dict офигенного размера и он тут на стеке вроде как иммутабельный. Как его теперь обработать из другого треда так, чтобы этот самый другой тред был уверен, что ему передают только иммутабельные объекты?

v> ·>И где что там у тебя автоматически гарантируется-то с помощью const?

v> В данном примере гарантируется, что переменная dict иммутабельная, хотя на этапе построения мы пошагово мутировали значение.
Это немного враньё. Значение мы мутировали у result, а dict это копия.

v> Но даже в процессе мутации ключи таблицы были гарантированно иммутабельны.

Потому что копии.

v> ·>Допустим, у тебя есть где-то const SomeThing someValue(42); — ты гарантируешь, что someValue — иммутабельно?

v> Без хаков если, то да.
И если из конструктора this не утекает, например.

v> v>> И для обычных даных это в точности равно иммутабельности.

v> ·>Повторюсь. Данные — не объекты (если я правильно понял, что ты подразумеваешь под данными). Мы говорим об объектах.
v> Ты опять разбрасываешься терминами.
v> Объект — это не только термин из ООП-парадигмы. В плюсах объектами является всё, даже простой int.
v> Данные/значения — это термин из механики происходящего, где by ref или by value имеют однозначную интерпретацию.
by value это скучный случай, но т.к. там копирование, то не всегда лучший.

v> ·>Приобретаемым как? Только заботой программиста. Компайлер c const ничего гарантировать не может.


v> Здесь оператор new возвращает указатель на неконстантный объект, но мы его сохраняем в указатель на константный объект.

v> Если конструктор SomeObject не имеет побочных эффектов (не сохраняет указатель на себя где-нить в глобальной переменной, т.е. если нет протечек), то гарантии получаются железобетонные.
Это тавтология какая-то. "Если гарантии есть, то гарантии есть". Вопрос и состоит в том — откуда собственно берутся эти гарантии отсутствия побочек и протечек? Ответ — обеспечиваются программистом. Вывод —
ты словоблудишь, т.к. речь идёт о гарантиях, даваемых компилятором.

Более того, в реальном коде могут быть и чуть менее тривиальные куски кода, стоит чуток порефакторить и вместо const SomeObject * obj = new SomeObject(); сделать const SomeObject * obj = makeSomeObject(); — так компилятору становится вообще плевать на все твои const-старания. А в том же шарпе ImmutableList означает именно что иммутабельный список и ничего более, со 100% гарантией компилятора, без всяких допущений и недосказок.

v> ·>В java record — гарантии есть, кстати.

v> Я ж не против, чтобы компилятор помогал программисту.
v> Это его прямая обязанность. ))
Угу. Верно. И в данном случае в java компилятор помогает больше. Наличие record тебе даёт гарантированно иммутабельный тип, и протечек никаких быть не может.

v> Да, в плюсах можно разрабатывать достоверно иммутабельные типы данных:

v> автоматом унаследовав всю инфраструктуру вокруг исходного типа, например, вычисление хеш-функции.
В java вместо этой всей колбасы в коде будет только @Builder record Index(int a, int b){} — создастся два типа — сам иммутабельный record и builder для него. Может не так красиво, зато билдер делается не в спеке ЯП, а либой.

v> По константной ссылке/указателю ты можешь ссылаться на мутабельные и иммутабельные объекты, делая код ортогональным для данных.

Ага. Но не получается сделать ссылку на иммутабельный объект.

v> ·>Это ложится на программиста, что в плюсах, что в джаве, что в шарпах. const для иммутабельности не нужен. Нужен record.

v> Это вам в джаве нужен, т.к. иммутабельность обеспечивается прикладной семантикой, где record — лишь синтаксический сахар для такой семантики.
Ну не совсем. В java обычно не делают что-то ради одной цели. records ввели в яп ещё и для реализации pattern matching.

v> Но в типе SomeDictionary const index резко становится иммутабельным.

Этот случай, кстати, поинтереснее. Т.к. это не голая структура, а есть куча всяких методов. И, внезапно, выясняется, что хоть и "резко", но уже не нахаляву — интерфейс SomeDictionary уже надо внимательно проектировать с разделением const/nonconst методов.

v> — ссылки на константные данные не гарантируют константность тех данных, они накладывают ограничения — позволяют использовать лишь иммутабельное АПИ объектов.

константное, а не иммутабельное. Не жонглируй терминами.

v> Как именно данные случаются неизменяемыми — да как угодно.

v> Можно и безо-всяких const, record, final и прочих приблуд, достаточно того, чтобы в момент работы таких алгоритмов данные никто не изменял.
Гарантию "никто не изменял" компилятор может дать лишь для иммутабельных типов.

v> Тут мы рассуждаем лишь о том, как защититься от случайного изменения невнимательным программистом данных, которые мы хотим рассматривать как иммутабельные.

Так это константность называется, а не иммутабельность, опять термины поменяешь.

Если же прекратить черри-пикать факты, то надо рассуждать не лишь о том, что тебе по душе, но и об остальных аспектах, и ещё порассуждать о том не как "хотим рассматривать", а как иметь иммутабельность с гарантией компилятора.

v> В общем, подход плюсов оказался настолько удобным, что его перетянули и в C# (но только для value-типов) и даже в последние версии FreePascal.

v> Ранее в этих языках был доступен только подход джавы.
Не очень понял, что ты имеешь в виду перетянулы в шарп?

v> ·>Нет, не подмножеством. read-only view для мутабельного объекта — не подмножество иммутабельного сценария, ну никак.

v> Еще как подмножество.
Я привёл явный пример когда это не так.

v> v>> И на выходе у нас комбинаторика сценариев, а не сумма их.

v> ·>Осталось понять ценность этого комбинаторного усложнения на ровном месте
v> Наоборот, упрощение, бо комбинаторный подход позволяет упростить базу — меньше писать.
Даже по количеству буковок не сильно отличается.

v> Одним и тем же кодом в плюсах ты можешь проходиться по мутабельному и иммутабельному дереву, например.

v> В джаве тебе пришлось бы делать два типа дерева и два кода для их обхода (или выкручиваться через интерфйесы, что утяжеляет/тормозит).
Я уже об этом упоминал. Нет никакого утяжеления. Интерфейсы в яве практически бесплатны.

v> ·>константность — не является необходимостью

v> Разумеется, константность не является необходимостью для иммутабельных сценариев.
v> Она лишь дико экономит труд програмиста и размер конечного бинаря, а так-то фигня полная.
Не экономит она труд. Насчёт размера тут тоже сложно всё. Неясно как можно адекватно сравнивать бинари плюсов и явы... слишком много нюансов.

v> ·>и можно нафиг выкинуть, что собственно и сделали в шарпах-явах.

v> Наоборот, в шарпе вот относительно недавно добавили.
v> А потом опять добавили.
v> Ключевое слово чуть другое — readonly, но смысл и сценарии использования те же.
Если я правильно помню, то это аналог final-поля, который был в java с рождения.

v> ·>Тогда нафиг никакой комбинаторики и всё просто.

v> Сложнее, обычно.
v> Причём, гораздо.
v> Вплоть до того, что даже в иммутабельных сценариях в джаве редко кто заморачивается с внутренней гарантией этой иммутабельности.
Не понимаю что ты понимаешь под сложностью.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[115]: Когда это наконец станет defined behavior?
От: vopl Россия  
Дата: 03.09.23 16:46
Оценка:
Здравствуйте, vdimas, Вы писали:

Я уже сдался, ты уже победил.
Автор: vopl
Дата: 22.08.23
Нет смысла дополнительно дискутировать.
Re[90]: Когда это наконец станет defined behavior?
От: vdimas Россия  
Дата: 04.09.23 12:53
Оценка:
Здравствуйте, ·, Вы писали:

v>> ·>покажи пример кода как обеспечить иммутабельность через view мутабельного объекта.

v>> Легко — достаточно обеспечить отсутствие протекание ссылки на мутабельный объект.
v>> (например, создавать приватный мутабельный объект в конструкторе view)
·>Не очень понял что ты имеешь в виду, продемонстрируй кодом.

Берёшь достаточно сложный мутабельный объект и прикручиваешь сверху иммутабельный view.
Один из популярных сценариев — какой-нить глобальный справочник.
На шарпе пара способов:
////////////////////////////////
public struct ReadOnlyDictionary<TKey, TValue> where TKey : notnull 
{
    private Dictionary<TKey, TValue> _dict;
  
    public int Count => _dict.Count;

    public TValue this[TKey key] => _dict[key];

    // наполняем приватный словарь в конструкторе
    public ReadOnlyDictionary((TKey key, TValue value)[] data)
        => _dict = data.ToDictionary(item => item.key, item => item.value);

    // обёртка над существующим словарём -
    //   потенциально небезопасная конструкция, поэтому приватная
    private ReadOnlyDictionary(Dictionary<TKey, TValue> dict) 
        =>_dict = dict;

    // пусть программист выражает намерения явно
    public static ReadOnlyDictionary<TKey, TValue> Wrap(Dictionary<TKey, TValue> dict) 
        => new(dict);
}

////////////////////////////////
public static class SomeSubsystem 
{
    private static (int key, string value)[] GetData() => new (int, string)[] {
        (42, "42"), 
        (43, "43")
    };

    // храним и возвращаем иммутабельный view
    public static ReadOnlyDictionary<int, string> Dict1 { get; } = new(GetData());

    // храним приватный мутабельный словарь
    private static Dictionary<int, string> dict2 = GetData().ToDictionary(item => item.key, item => item.value);

    // возвращаем публичную иммутабельную обертку над приватным мутабельным объектом
    public static ReadOnlyDictionary<int, string> Dict2 => ReadOnlyDictionary<int, string>.Wrap(dict2);
}

////////////////////////////////
class Program
{
    static void Main() {
         Console.WriteLine(SomeSubsystem.Dict1[42]);
         Console.WriteLine(SomeSubsystem.Dict2[43]);
    }
}



v>> ·>Вопрос в том, как же компилятор проверяет/помогает гарантировать отстуствие протечек с помощью const?

v>> Достаточно просто — объявляешь данные как const и они автоматом становятся иммутабельными.
·>А дальше что? В лучшем случае ты их можешь такими сделать в пределах локальной переменной или поля класса.

Для глобальных переменных аналогично.


·>В другом скопе он уже теряет иммутабельность.


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


v>> Иммутабельность автоматически распространяется при владении другими объектами по-значению.

·>По значению это и есть defensive copy.

Э, нет. ))
Это в джаве такая техника, связанная с тем, что все объекты имеют ссылочную семантику.
Тогда, если объект не предоставляет явного read-only АПИ, необходимо создавать его копию при подаче такого объекта в кач-ве аргументов, чтобы вызываемый код не изменил состояние вызывающего кода.

В этом месте я и стебался, что в джаве не всегда даже заморачиваются с такими вещами — банально можно прохлопать или полениться, типа, вызывающий код достоверно не изменяет аргументы... а потом оп-па при очередных изменениях — получи фашист гранату! ))

В дотнете такие вещи обыгрываются автоматически через value-type, где при передаче по-значению копия создаётся автоматом.
Второй способ — это передача readonly-ссылки на value-type значение.

Первый способ является defensive copy, второй способ заимствован у плюсов (причём, относительно недавно).

Ну и, для GC-объектов в дотнете ситуация ровно как в джаве и решается точно так же.


v>> ·>Ответ — да никак.

v>> Для этого необходимо показать хотя бы минимальный пример этого "никак".
·>Пример чего? Пример кода, который никак не написать??!

Пример нарушения иммутабельности константного объекта.


v>> ·>Важное свойство иммутабельных объектов в том, что их копии никак не отличимы от оригинала и копирование можно избегать.

v>> Это лишь один из трюков, достижимых при иммутабельности.
v>> Так же как шаренье иммутабельных данных без блокировки м/у потоками.
·>Угу. А константные объекты даже пошарить нельзя.

Константные объекты не можно, а нужно шарить. ))
Собсно, зачастую для таких сценариев константные объекты и используются, включая обычные константы.


v>> Но иммутабельные данные необходимо как-то создавать.

v>> И наиболее эффективно их создавать в мутабельной манере.
v>> Я уже отсылал к паттерну mutable_builder => immutable_object.
·>Да, но там создаётся иммутабельная копия из данных мутабельного билдера. Как и в шарпах всяческих.

Есть еще несколько вариантов:

  • Данные не пересоздаются в конце работы builder, а меняют своего владельца, сам builder помечает этот факт в данных и, если построение данных продолжится после выдачи иммутабельного объекта, то builder создаст себе новую копию данных для дальнейшего над ними измывательства;

    Этот способ в дотнете мейнстримовый — так работает StringBulder и билдеры иммутабельных коллекций, т.е. сделано то предположение, что после порождения иммутабельного объекта дальнейшее построение ведется редко, поэтому оптимизирован этот сценарий;

  • Данные в конце работы builder меняют своего владельца, при этом сам builder обнуляется. Дальнейшее построение либо невозможно, либо ведётся с нуля.

    Тут происходит экономия на флагах в самих данных (флаги помечают — рассматриваются ли данные уже как иммутабельные или еще нет).

    Например, для иммутабельных деревьев в шарпе такая пометка живёт в каждом узле, что для некоторых сценариев накладно (дерево большое и является более init-only, чем CRUD). В этом случае заруливает всё и вся read-only view над данными, как показал в примере выше.


    v>> Вот после создания иммутабельного объекта, все эти трюки можно использовать.

    ·>С иммутабельным можно. С константным — не всегда, только компилятор гарантии не даёт.

    Я попросил пример, где компилятор не даёт гарантии.

    v>> ·>Как и в Плюсах.

    v>> В плюсах компилятор больно бъёт тебе по пальцам.
    ·>Компилятор ничего про иммутабельность не знает, поэтому по пальцам бить тупо не может. Нет такого понятия в стандарте.

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


    ·>ИЧСХ, ты это и так прекрасно понимаешь (когда, например, ты скромно "забыл" назвать объект типа const SomeObj иммутабельным). Я не понимаю зачем ты тут этот цирк устраиваешь?


    На самом деле я нифига не понимаю твою логику.
    Смешались в кучу люди, кони...

    Если тебе это действительно интересно, то стоило разбирать конкретные сценарии, конструкции языка и оценивать получаемые гарантии.
    Тогда обсуждение было бы более предметным.

    А вот это твоё переливание из пустого в порожнее чиста на словах/эмоциях...


    v>> Собсно, новички в плюсах зачастую маются с компиллированием программ именно из-за попыток нарушения константности.

    ·>Это, кстати, тоже минус.

    Этот минус живёт пару дней обычно у новичка.
    Затем сплошной плюс плюс. ))


    ·>С интерфейсами же всё проще — есть метод, можно дёрнуть, нет метода — нельзя дёрнуть.


    Ну... если бы существовал идеально сбалансированный ЯП, не было бы так много других. ))

    Увы, каждый язык заточен не только под конкретные сценарии, но и под конкретный образ мысли программиста, и даже под его уровень.
    В некоторые языки "порог входа" ниже, но и возможностей в некоторых задачах меньше.
    За всё надо платить...


    v>> ·>Ровно твои слова же: "Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность". К чему сарказм-то?

    v>> К тому, что компилятор в плюсах отслеживает попытки "протечек" и отказывается компилировать такой код.
    ·>Не отслеживает. Сам же ниже пишешь, например, о сценарии утечки this из конструктора.

    Это классический побочный эффект.
    Тоже иногда сильная и нужная весчь, просто не всегда сочетается с иммутабельными сценариями.

    Чтобы сочетать побочные эффекты с иммутабельностью, данные надо сразу описывать как иммутабельные (init-only), т.е. все поля объекта должны быть const и инициализироваться до тела конструктора (в списке инициализации переменных), т.е. до возможности оперировать переменной this.

    Тогда строгая иммутабельность объекта будет обеспечена даже без ключевого слова const перед переменной его типа. ))

    Но это крайний случай, который не сильно интересен, потому что не получаем плюшек выразительности/обобщения.
    Такая возможность "просто есть", но используется редко, бо редко надо совмещать иммутабельность с побочными эффектами.
    Но зато когда надо — понятно что делать.


    v>> ·>Вопрос в том, как собственно обеспечить отсутствие протечек.

    v>> result[{42, 43}] = "42, 43";
    ·>Здесь формально копиктор struct срабатывает.

    Здесь сам словарь мутабельный, ключ словаря иммутабельный, данные по ключу перезаписываемы.
    result[index] возвращает non-const ссылку на значение, по этой ссылке происходит присвоение нового значения.

    Кстате, operator[] для map в плюсах имеет non-const сигнатуру и это порой неудобно.
    Можно было добавить рядом аналогичную const-сигатуру и возвращать константную ссылку, потому как это сделано для метода at.

    Т.е. можно было так:
    value & operator[](const key & index) { ... }
    
    const value & operator[](const key & index) const { ... }

    Второй вариант вызывается для константных объектов, соответственно, присвоить по константной ссылке ничего нельзя (это не может быть left-value), можно только прочитать (right-value).


    v>> // но здесь иммутабельный объект

    v>> const SomeDictionary dict = buildDictionary();
    ·>И здесь формально копия.

    Формально копия, верно.
    А на деле никакой копии — дополнительные временные объекты не создаются.


    ·>Но допустим у тебя есть этот самый dict офигенного размера и он тут на стеке вроде как иммутабельный. Как его теперь обработать из другого треда так, чтобы этот самый другой тред был уверен, что ему передают только иммутабельные объекты?


    Это зависит от взаимного времени жизни — поток не должен пережить время жизни такой переменной (например, создали такую переменную в main и передали программе дальше).
    Или же такая переменная может быть глобальной/статической, как я и показал в примере.


    v>> В данном примере гарантируется, что переменная dict иммутабельная, хотя на этапе построения мы пошагово мутировали значение.

    ·>Это немного враньё. Значение мы мутировали у result, а dict это копия.

    Формально да.
    А на деле происходили операции в одной области памяти, т.е. получился классический кейз иммутабельных данных — init-only.

    В этом примере через формальное якобы создание копии разделяется время жизни мутабельной переменной result и иммутабельной переменной dict, где вторая становится доступной для оперирования строго после того, как переменная result стала недоступной. Хотя, обе переменные ссылаются на одну область памяти.

    Работает этот трюк за счёт того, что время жизни объекта не обязательно равно времени жизни переменной.
    Именно поэтому описание init-only сценариев настолько простое/элегантное — здравствуй выразительность! ))


    v>> Но даже в процессе мутации ключи таблицы были гарантированно иммутабельны.

    ·>Потому что копии.

    Это может быть копия указателя, как в джаве.
    Но тогда надо озаботиться распространением константности по указателям.


    v>> ·>Допустим, у тебя есть где-то const SomeThing someValue(42); — ты гарантируешь, что someValue — иммутабельно?

    v>> Без хаков если, то да.
    ·>И если из конструктора this не утекает, например.

    Выше отписывался по этому кейзу.


    v>> Данные/значения — это термин из механики происходящего, где by ref или by value имеют однозначную интерпретацию.

    ·>by value это скучный случай, но т.к. там копирование, то не всегда лучший.

    Зависит от размеров данных.
    Тут уже программист выбирает что эффективней — распространять ссылки и иметь косвенность на стороне вычислений, или распространять копии небольших объектов, где вычисления над ними происходят эффективней.


    v>> Здесь оператор new возвращает указатель на неконстантный объект, но мы его сохраняем в указатель на константный объект.

    v>> Если конструктор SomeObject не имеет побочных эффектов (не сохраняет указатель на себя где-нить в глобальной переменной, т.е. если нет протечек), то гарантии получаются железобетонные.
    ·>Это тавтология какая-то. "Если гарантии есть, то гарантии есть". Вопрос и состоит в том — откуда собственно берутся эти гарантии отсутствия побочек и протечек? Ответ — обеспечиваются программистом. Вывод —
    ·>ты словоблудишь, т.к. речь идёт о гарантиях, даваемых компилятором.

    Я уже упомянул вариант сделать все поля объекта const.
    Т.е. возможность получить железобетонные гарантии тоже есть.
    Тогда, даже если this протечёт, через этот this невозможно будет изменить init-only данные.

    Тут удобней рассуждать о "чистых функциях" (в том числе о конструкторах/деструкторах) и такие обсуждения ведутся.
    Например, в некоторые языки добавляют ключевое слово clean, которое может дать обсуждаемые гарантии отсутствия протечек.


    ·>Более того, в реальном коде могут быть и чуть менее тривиальные куски кода, стоит чуток порефакторить и вместо const SomeObject * obj = new SomeObject(); сделать const SomeObject * obj = makeSomeObject(); — так компилятору становится вообще плевать на все твои const-старания. А в том же шарпе ImmutableList означает именно что иммутабельный список и ничего более, со 100% гарантией компилятора, без всяких допущений и недосказок.


    Тогда обернуть объект в read-only view.


    ·>Угу. Верно. И в данном случае в java компилятор помогает больше. Наличие record тебе даёт гарантированно иммутабельный тип, и протечек никаких быть не может.


    Угу, теперь построй на своих record реализацию иммутабельного словаря (в т.ч. хеш-таблицы) или приоритетной очереди.


    v>> Да, в плюсах можно разрабатывать достоверно иммутабельные типы данных:

    v>> автоматом унаследовав всю инфраструктуру вокруг исходного типа, например, вычисление хеш-функции.
    ·>В java вместо этой всей колбасы в коде будет только @Builder record Index(int a, int b){} — создастся два типа — сам иммутабельный record и builder для него. Может не так красиво, зато билдер делается не в спеке ЯП, а либой.

    Это всё понятно, если самому всё с 0-ля писать (и то, вопрос выше в силе).
    Непонятно как использовать тысячи уже готовых типов в имммутабельных сценариях.

    В плюсах это делается относительно дешево, а мы тут обсуждаем лишь цену, бо возможность описать на любом достаточно развитом ЯП иммутабельные сценарии я под сомнение не ставил.


    v>> По константной ссылке/указателю ты можешь ссылаться на мутабельные и иммутабельные объекты, делая код ортогональным для данных.

    ·>Ага. Но не получается сделать ссылку на иммутабельный объект.

    Абсолютно верно.
    Эта ссылка может ссылаться как на мутабельный, так и на иммутабельный объект.

    Следовательно, гарантии происходят от того, кто эту ссылку передаёт во внешний мир — ведь только владелец данных "знает" характер своих данных.
    А выполняемый read-only код единообразен (например, банальное логирование), отсюда ортогональность кода к данным.


    v>> ·>Это ложится на программиста, что в плюсах, что в джаве, что в шарпах. const для иммутабельности не нужен. Нужен record.

    v>> Это вам в джаве нужен, т.к. иммутабельность обеспечивается прикладной семантикой, где record — лишь синтаксический сахар для такой семантики.
    ·>Ну не совсем. В java обычно не делают что-то ради одной цели. records ввели в яп ещё и для реализации pattern matching.

    Это, скорее, следствие.
    И вообще, отдельная тема.
    В какую-то версию шарпа ввели Deconstruct для паттерн-матчинга (который матчил только туплы и рекорды, на манер которых позже сделали джавовские)... А потом допилили паттерн-матчинг до спецификации полей через is { Field1 == X }, что теперь Deconstruct стал не нужным, бгг...


    v>> Но в типе SomeDictionary const index резко становится иммутабельным.

    ·>Этот случай, кстати, поинтереснее. Т.к. это не голая структура, а есть куча всяких методов. И, внезапно, выясняется, что хоть и "резко", но уже не нахаляву — интерфейс SomeDictionary уже надо внимательно проектировать с разделением const/nonconst методов.

    Ес-но.
    Но это всё еще одно описание типа, где ты просто помечаешь read-only методы через const.

    У плюсовиков этот рефлекс на уровне мозжечка, бо является еще дополнительным документированием/аннотированием методов — профит! ))
    "Читать" такие типы потом проще.


    v>> — ссылки на константные данные не гарантируют константность тех данных, они накладывают ограничения — позволяют использовать лишь иммутабельное АПИ объектов.

    ·>константное, а не иммутабельное. Не жонглируй терминами.

    Никакого жонглирования, бо здесь речь не об неизменяемых данных, а об неизменяемой обработке данных, т.е. не вносящих в данные изменения.
    Просто не надо складывать в кучу неизменяемые данные и алгоритмы, не изменяющие даные.
    (просил уже)


    v>> Как именно данные случаются неизменяемыми — да как угодно.

    v>> Можно и безо-всяких const, record, final и прочих приблуд, достаточно того, чтобы в момент работы таких алгоритмов данные никто не изменял.
    ·>Гарантию "никто не изменял" компилятор может дать лишь для иммутабельных типов.

    Это всё до некоторой степени, пока не пошли хаки, например, через реинтерпретацию памяти или рефлексию.

    Лишь малое кол-во языков способно обеспечить доказуемость корректности своего кода.
    И ведь не просто так эти языки нифига не мейнстримовые?

    Любой современный мейнстрим — всегда компромисс.
    Т.е., строго говоря, мы обсуждаем лишь удобство организации этого компромисса.
    Ту самую "выразительность" и ничего более, держа в уме, что речь идёт о, таки, мультипарадигменных, т.е. слишком компромиссных ЯП.
    (да, современную джаву можно уже называть мультипарадигменной, и чем дальше, тем больше — осталось дело за малым — узаконить функциональный тип в языке, бгг)


    v>> Тут мы рассуждаем лишь о том, как защититься от случайного изменения невнимательным программистом данных, которые мы хотим рассматривать как иммутабельные.

    ·>Так это константность называется, а не иммутабельность, опять термины поменяешь.

    Разве?

    Неизменяемым (англ. immutable) называется объект, состояние которого не может быть изменено после создания.

    В языках программирования C, C++, C# и D const является квалификатором типа: ключевое слово применяется к типу данных, показывая, что данные константны (неизменяемы).

    Если бы ключевое слово было не const, а immutable — тебе было бы легче? ))


    ·>Если же прекратить черри-пикать факты, то надо рассуждать не лишь о том, что тебе по душе, но и об остальных аспектах, и ещё порассуждать о том не как "хотим рассматривать", а как иметь иммутабельность с гарантией компилятора.


    Гарантии в любом случае недоказуемы в обсуждаемых языках.

    В джаве можно допустить ошибку — изменив данные через некий метод интерфейса, который (интерфейс) согласно прикладной семантики должен был давать read-only view.
    В плюсах можно забыть приписать полю const и однажды наступить в это, и т.д. до бесконечности.

    Более конструктивно будет обсуждать такой вариант, где программист выразил свои намерения верно и обеспечил "железобетонные гарантии".
    (которые всё-равно обходятся через хаки и в джаве, и в плюсах, но мы об этом скромно умалчиваем, бгг).

    В этих вариантах останется обсуждать лишь выразительность (т.е. трудоёмкость готового решения) и ничего более.


    v>> В общем, подход плюсов оказался настолько удобным, что его перетянули и в C# (но только для value-типов) и даже в последние версии FreePascal.

    v>> Ранее в этих языках был доступен только подход джавы.
    ·>Не очень понял, что ты имеешь в виду перетянулы в шарп?

    В шарпе появились константные ссылки — "readonly ref", или кратко "in" для параметров (применяется для value-типов и для переменных-ссылок на GC-типы), а так же полные аналоги const-методов из плюсов — это "readonly" методы у value-типов.

    Для борьбы с потенциальными протечками локальных ссылок ввели ref struct — это такие value-типы, которые могут жить только на стеке.
    А так же ввели инструмент контроля за протечками — ключевое слово scoped.
    Более подробно расписано в доке, там достаточно интересно. ))

    Всё вместе служит той же цели — выразительности кода при достижении тех или иных гарантий.


    v>> ·>Нет, не подмножеством. read-only view для мутабельного объекта — не подмножество иммутабельного сценария, ну никак.

    v>> Еще как подмножество.
    ·>Я привёл явный пример когда это не так.

    Не видел.
    И оно не может быть "не так" согласно определению иммутабельности и семантики кода, получающего read-only доступ к данным.


    v>> Наоборот, упрощение, бо комбинаторный подход позволяет упростить базу — меньше писать.

    ·>Даже по количеству буковок не сильно отличается.

    Не скажи.))

    Я привёл примёр read-only view на шарпе (на джаве можно аналогично, разве что +1 к косвенности), а в плюсах достаточно было простого ключевого слова const безо всей этой возни.


    v>> Одним и тем же кодом в плюсах ты можешь проходиться по мутабельному и иммутабельному дереву, например.

    v>> В джаве тебе пришлось бы делать два типа дерева и два кода для их обхода (или выкручиваться через интерфйесы, что утяжеляет/тормозит).
    ·>Я уже об этом упоминал. Нет никакого утяжеления. Интерфейсы в яве практически бесплатны.

    Вранье. ))
    Интерфейсы в джаве намного тяжелее прямых методов.
    Бесплатны они только если компилятор или JIT "видят" жизненный цикл ссылки — тогда может заменить вызов метода через интерфейс прямым вызовом.
    В плюсах аналогично.

    Стоимость же честного вызова интерфейса в плюсах дешевле, бо в плюсах объект ссылается на свою vtable явно, а в джаве и шарпе — через промежуточный дескриптор типа, т.е. +1 к косвенности, в сравнении с плюсами.


    v>> ·>константность — не является необходимостью

    v>> Разумеется, константность не является необходимостью для иммутабельных сценариев.
    v>> Она лишь дико экономит труд програмиста и размер конечного бинаря, а так-то фигня полная.
    ·>Не экономит она труд.

    Выше пример, который не нужен в плюсах.


    ·>Насчёт размера тут тоже сложно всё. Неясно как можно адекватно сравнивать бинари плюсов и явы... слишком много нюансов.


    Надо сравнивать бинари в рамках одной техонлогии.
    Например, можно сравнивать бинари в плюсах при применении подхода джавы vs родного плюсового подхода.
    Или можно сравнивать бинари в шарпе, где доступны оба подхода для value-типов.

    В любом случае, лишний код есть лишний код.


    v>> ·>и можно нафиг выкинуть, что собственно и сделали в шарпах-явах.

    v>> Наоборот, в шарпе вот относительно недавно добавили.
    v>> А потом опять добавили.
    v>> Ключевое слово чуть другое — readonly, но смысл и сценарии использования те же.
    ·>Если я правильно помню, то это аналог final-поля, который был в java с рождения.

    Это изначально применительно к полям объектов.
    Затем readonly стало можно применять к аргументам методов и возвращаемым значениям.
    Затем через readonly стало можно помечать методы, где этот метод не может изменять внутренние поля — компилятор не даст.


    v>> Вплоть до того, что даже в иммутабельных сценариях в джаве редко кто заморачивается с внутренней гарантией этой иммутабельности.

    ·>Не понимаю что ты понимаешь под сложностью.

    Лишний код.
    Тот же твой Defensive copying как малая часть этой сложности.
    Например, в дотнете достаточно передавать DateTime по значению или по константной ссылке, а в джаве надо делать GC-копию объекта на каждый чих.
    Да там уже просто рука устаёт всё это внимательно описывать. ))
  • Отредактировано 04.09.2023 16:26 vdimas . Предыдущая версия . Еще …
    Отредактировано 04.09.2023 13:09 vdimas . Предыдущая версия .
    Отредактировано 04.09.2023 13:07 vdimas . Предыдущая версия .
    Отредактировано 04.09.2023 13:05 vdimas . Предыдущая версия .
    Отредактировано 04.09.2023 13:03 vdimas . Предыдущая версия .
    Отредактировано 04.09.2023 13:00 vdimas . Предыдущая версия .
    Отредактировано 04.09.2023 13:00 vdimas . Предыдущая версия .
    Re[91]: Когда это наконец станет defined behavior?
    От: · Великобритания  
    Дата: 05.09.23 11:16
    Оценка: -1 :)
    Здравствуйте, vdimas, Вы писали:

    v>>> ·>покажи пример кода как обеспечить иммутабельность через view мутабельного объекта.

    v>>> Легко — достаточно обеспечить отсутствие протекание ссылки на мутабельный объект.
    v>>> (например, создавать приватный мутабельный объект в конструкторе view)
    V>·>Не очень понял что ты имеешь в виду, продемонстрируй кодом.
    V>Берёшь достаточно сложный мутабельный объект и прикручиваешь сверху иммутабельный view.
    Ясно. Просто ты опять плаваешь в терминологии и делаешь странные обобщения. Тут у тебя не "иммутабельность может быть св-вом объекта, а может быть адаптером-view", а "иммутабельность может быть обёрткой мутабельного типа", тупо инкапсуляция. В этом принципиальное отличие от константности, ведь константность действительно можно обеспечить "через view мутабельного объекта" — т.е. во view оборачивается инстанс типа (т.е. объект).

    И вот тут я опять подозреваю, что ты нарочно флейм разводишь и цирк устраиваешь. Я попросил продемонстрировать "пример кода как обеспечить иммутабельность", а ты мне вываливаешь ReadOnlyDictionary, как нарочно мешаешь всё в кучу: кручу, верчу, запутать хочу.
    Или ты вообще невдупляешь что такое иммутабельность. Если так, то почитай доку .NET чем отличаются IImmutableDictionary и IReadOnlyDictionary.

    v>>> Достаточно просто — объявляешь данные как const и они автоматом становятся иммутабельными.

    V>·>А дальше что? В лучшем случае ты их можешь такими сделать в пределах локальной переменной или поля класса.
    V>Для глобальных переменных аналогично.
    А, ну да, забыл про это. Ибо глобальные переменные — зло.

    V>·>В другом скопе он уже теряет иммутабельность.

    V>Если речь про эти же самые данные — то иммутабельность не теряется.
    Теряется с т.з. компилятора. Иммутабельность данных по конст-ссылкам никак не гарантируется компилятором.

    V>Но можно получить мутабельную копию данных (в общем случае, если не запрещать конструктор копирования), где изменения в копии не будут влиять на исходные данные.

    Дело не в этом. Дело в том, что все те ништяки, которые имеются у иммутабельных типов — исчезают, т.к. имея даже "const X" нельзя быть уверенным — иммутабельный он или нет. И совсем плохо, если у тебя "const X*" — тут вообще беда.

    V>·>По значению это и есть defensive copy.

    V>Э, нет. ))
    V>Это в джаве такая техника, связанная с тем, что все объекты имеют ссылочную семантику.
    Нет. Вот это твоё "data.ToDictionary(item => item.key, item => item.value)" — и есть defensive copy — ты копируешь данные внтурь объекта и не даёшь к ним мутирующий доступ, инкапсуляция обычная. А твоё "Wrap(Dictionary<TKey, TValue> dict) => new(dict)" — это бага. Оно тоже копию должно создавать, иначе это вовсе не иммутабельный тип как ты обещал выше, а ReadOnly view.

    V>Тогда, если объект не предоставляет явного read-only АПИ, необходимо создавать его копию при подаче такого объекта в кач-ве аргументов, чтобы вызываемый код не изменил состояние вызывающего кода.

    Только иммутабельность для этого не нужна, для этого достаточно константности. И даже копию делать вовсе не обязательно — можно просто RO-view обёртку для того же объекта.

    V>В этом месте я и стебался, что в джаве не всегда даже заморачиваются с такими вещами — банально можно прохлопать или полениться, типа, вызывающий код достоверно не изменяет аргументы... а потом оп-па при очередных изменениях — получи фашист гранату! ))

    Не заморачиваются, как правило, для простоты, из-за лени...

    V>В дотнете такие вещи обыгрываются автоматически через value-type, где при передаче по-значению копия создаётся автоматом.

    В дотнете создают ImmutableList, ReadOnlyCollection, string/StringBuilder и т.п. Иначе получается фигня, как у тебя в плюсах.

    V>Второй способ — это передача readonly-ссылки на value-type значение.

    Опять же read-only. Мы говорим об иммутабельности же.


    v>>> ·>Ответ — да никак.

    v>>> Для этого необходимо показать хотя бы минимальный пример этого "никак".
    V>·>Пример чего? Пример кода, который никак не написать??!
    V>Пример нарушения иммутабельности константного объекта.
    Через утечку this в конструкторе, например, ты же сам этот код где-то выше показывал. Или вообще — запустили в конструкторе новый тред и меняем там this когда захочется. А компилятору — пофиг.

    v>>> Это лишь один из трюков, достижимых при иммутабельности.

    v>>> Так же как шаренье иммутабельных данных без блокировки м/у потоками.
    V>·>Угу. А константные объекты даже пошарить нельзя.
    V>Константные объекты не можно, а нужно шарить. ))
    V>Собсно, зачастую для таких сценариев константные объекты и используются, включая обычные константы.
    Но там, где они пошарены — уже нельзя рассчитывать на плюшки иммутабельости.

    V>·>Да, но там создаётся иммутабельная копия из данных мутабельного билдера. Как и в шарпах всяческих.

    V>Есть еще несколько вариантов:
    V>* Данные не пересоздаются в конце работы builder, а меняют своего владельца, сам builder помечает этот факт в данных и, если построение данных продолжится после выдачи иммутабельного объекта, то builder создаст себе новую копию данных для дальнейшего над ними измывательства;
    V>* Данные в конце работы builder меняют своего владельца, при этом сам builder обнуляется. Дальнейшее построение либо невозможно, либо ведётся с нуля.
    Это уже мелкие оптимизации. Со своими преимуществами. И недостатками (которые ты скромно умалчиваешь).

    v>>> Вот после создания иммутабельного объекта, все эти трюки можно использовать.

    V>·>С иммутабельным можно. С константным — не всегда, только компилятор гарантии не даёт.
    V>Я попросил пример, где компилятор не даёт гарантии.
    Я показал выше.

    v>>> ·>Как и в Плюсах.

    v>>> В плюсах компилятор больно бъёт тебе по пальцам.
    V>·>Компилятор ничего про иммутабельность не знает, поэтому по пальцам бить тупо не может. Нет такого понятия в стандарте.
    V>Другой термин, бо в стандарте описаны конструкции языка, а не прикладная роль данных.
    Ну в яве почему-то не постеснялись написать "другой термин" (нет, не просто термин, а другая семантическая конструкция) в описании рекордов.

    V>·>ИЧСХ, ты это и так прекрасно понимаешь (когда, например, ты скромно "забыл" назвать объект типа const SomeObj иммутабельным). Я не понимаю зачем ты тут этот цирк устраиваешь?

    V>На самом деле я нифига не понимаю твою логику.
    V>Смешались в кучу люди, кони...
    V>Если тебе это действительно интересно, то стоило разбирать конкретные сценарии, конструкции языка и оценивать получаемые гарантии.
    V>Тогда обсуждение было бы более предметным.
    Курсивом выше и выделена твоя цитата из твоего сценария, поищи что ты там как назвал.

    v>>> ·>Ровно твои слова же: "Если протечек ссылок для мутабельности нет, то автоматом получается иммутабельность". К чему сарказм-то?

    v>>> К тому, что компилятор в плюсах отслеживает попытки "протечек" и отказывается компилировать такой код.
    V>·>Не отслеживает. Сам же ниже пишешь, например, о сценарии утечки this из конструктора.
    V>Это классический побочный эффект.
    V>Тоже иногда сильная и нужная весчь, просто не всегда сочетается с иммутабельными сценариями.
    Угу. Т.е. не отслеживает. ЧТД.

    V>Чтобы сочетать побочные эффекты с иммутабельностью, данные надо сразу описывать как иммутабельные (init-only), т.е. все поля объекта должны быть const и инициализироваться до тела конструктора (в списке инициализации переменных), т.е. до возможности оперировать переменной this.

    Или как final-поля в яве.

    V>Тогда строгая иммутабельность объекта будет обеспечена даже без ключевого слова const перед переменной его типа. ))

    Именно. const для иммутабельности не нужен.

    V>Но это крайний случай, который не сильно интересен, потому что не получаем плюшек выразительности/обобщения.

    V>Такая возможность "просто есть", но используется редко, бо редко надо совмещать иммутабельность с побочными эффектами.
    V>Но зато когда надо — понятно что делать.


    v>>> ·>Вопрос в том, как собственно обеспечить отсутствие протечек.

    v>>> result[{42, 43}] = "42, 43";
    V>·>Здесь формально копиктор struct срабатывает.
    V>Здесь сам словарь мутабельный, ключ словаря иммутабельный, данные по ключу перезаписываемы.
    V>result[index] возвращает non-const ссылку на значение, по этой ссылке происходит присвоение нового значения.
    Тут срабатыват копиктор структуры, как примерно вот так index key{42, 43}; result[key] = "42, 43";. Внутри мапы создаётся копия ключа.

    V>·>И здесь формально копия.

    V>Формально копия, верно.
    V>А на деле никакой копии — дополнительные временные объекты не создаются.
    На деле это необязательная оптимизация.

    V>·>Но допустим у тебя есть этот самый dict офигенного размера и он тут на стеке вроде как иммутабельный. Как его теперь обработать из другого треда так, чтобы этот самый другой тред был уверен, что ему передают только иммутабельные объекты?

    V>Это зависит от взаимного времени жизни — поток не должен пережить время жизни такой переменной (например, создали такую переменную в main и передали программе дальше).
    Ну дестркуторы отдельная тема. Деструктор, к сожалению, может поменять состояние даже супер-пупер константно-иммутабельного объекта.

    V>Или же такая переменная может быть глобальной/статической, как я и показал в примере.

    Проблема в том, что этот же тред потом можно будет внезапно вызвать с мутабельным объектом.

    v>>> В данном примере гарантируется, что переменная dict иммутабельная, хотя на этапе построения мы пошагово мутировали значение.

    V>·>Это немного враньё. Значение мы мутировали у result, а dict это копия.
    V>Формально да.
    V>А на деле происходили операции в одной области памяти, т.е. получился классический кейз иммутабельных данных — init-only.
    Это оптимизации всё. После jit тоже много чего интересного происходит.

    V>В этом примере через формальное якобы создание копии разделяется время жизни мутабельной переменной result и иммутабельной переменной dict, где вторая становится доступной для оперирования строго после того, как переменная result стала недоступной. Хотя, обе переменные ссылаются на одну область памяти.

    Это аналогично Dictionary result =...; IReadOnlyDictionary dict = result;, т.е. с таким же успехом описывается интерфейсом.

    V>Работает этот трюк за счёт того, что время жизни объекта не обязательно равно времени жизни переменной.

    V>Именно поэтому описание init-only сценариев настолько простое/элегантное — здравствуй выразительность! ))
    Чем это выразительнее интерфейса-то?

    v>>> Но даже в процессе мутации ключи таблицы были гарантированно иммутабельны.

    V>·>Потому что копии.
    V>Это может быть копия указателя, как в джаве.
    V>Но тогда надо озаботиться распространением константности по указателям.
    Я вроде выше уже демонстрировал как можно мутировать значение ключа на который ссылается таблица, сломав инвариант.
    А с другой стороны — имея в яве HashMap<String, XXX> можно быть 100% уверенным, что ключ поменяться не может.

    v>>> Без хаков если, то да.

    V>·>И если из конструктора this не утекает, например.
    V>Выше отписывался по этому кейзу.
    Ты это назвал побочным эффектом, и это, как ты считаешь, даёт индульгенцию, т.к. в твою картину мира не укладывается. Отличный пример черри-пикинга фактов.

    v>>> Данные/значения — это термин из механики происходящего, где by ref или by value имеют однозначную интерпретацию.

    V>·>by value это скучный случай, но т.к. там копирование, то не всегда лучший.
    V>Зависит от размеров данных.
    V>Тут уже программист выбирает что эффективней — распространять ссылки и иметь косвенность на стороне вычислений, или распространять копии небольших объектов, где вычисления над ними происходят эффективней.
    Угу. Я и говорю "не всегда".

    V>·>Это тавтология какая-то. "Если гарантии есть, то гарантии есть". Вопрос и состоит в том — откуда собственно берутся эти гарантии отсутствия побочек и протечек? Ответ — обеспечиваются программистом. Вывод —

    V>·>ты словоблудишь, т.к. речь идёт о гарантиях, даваемых компилятором.
    V>Я уже упомянул вариант сделать все поля объекта const.
    V>Т.е. возможность получить железобетонные гарантии тоже есть.
    V>Тогда, даже если this протечёт, через этот this невозможно будет изменить init-only данные.
    Что будет фактическим аналогом сделать все поля final.

    V>Тут удобней рассуждать о "чистых функциях" (в том числе о конструкторах/деструкторах) и такие обсуждения ведутся.

    V>Например, в некоторые языки добавляют ключевое слово clean, которое может дать обсуждаемые гарантии отсутствия протечек.
    Угу. Я рад, что ты наконец-то согласился, что гарантий в плюсах для этого нет.

    V>·>Более того, в реальном коде могут быть и чуть менее тривиальные куски кода, стоит чуток порефакторить и вместо const SomeObject * obj = new SomeObject(); сделать const SomeObject * obj = makeSomeObject(); — так компилятору становится вообще плевать на все твои const-старания. А в том же шарпе ImmutableList означает именно что иммутабельный список и ничего более, со 100% гарантией компилятора, без всяких допущений и недосказок.

    V>Тогда обернуть объект в read-only view.
    Как и в явах всяких. О чём я и говорил, много раз уже.

    V>·>Угу. Верно. И в данном случае в java компилятор помогает больше. Наличие record тебе даёт гарантированно иммутабельный тип, и протечек никаких быть не может.

    V>Угу, теперь построй на своих record реализацию иммутабельного словаря (в т.ч. хеш-таблицы) или приоритетной очереди.
    Это уже совсем бред какой-то. Даже в эрлангах-хаскеллях такое не делают, ибо нафиг надо.

    v>>> автоматом унаследовав всю инфраструктуру вокруг исходного типа, например, вычисление хеш-функции.

    V>·>В java вместо этой всей колбасы в коде будет только @Builder record Index(int a, int b){} — создастся два типа — сам иммутабельный record и builder для него. Может не так красиво, зато билдер делается не в спеке ЯП, а либой.
    V>Это всё понятно, если самому всё с 0-ля писать (и то, вопрос выше в силе).
    V>Непонятно как использовать тысячи уже готовых типов в имммутабельных сценариях.
    С осторожностью, как и в плюсах.

    V>В плюсах это делается относительно дешево, а мы тут обсуждаем лишь цену, бо возможность описать на любом достаточно развитом ЯП иммутабельные сценарии я под сомнение не ставил.

    Так и в шарпах-явах это делается относительно дёшево. Даже неясно относительно чего ты тут дешевизну намерил.

    v>>> По константной ссылке/указателю ты можешь ссылаться на мутабельные и иммутабельные объекты, делая код ортогональным для данных.

    V>·>Ага. Но не получается сделать ссылку на иммутабельный объект.
    V>Абсолютно верно.
    V>Эта ссылка может ссылаться как на мутабельный, так и на иммутабельный объект.
    В этом и беда. Поэтому иммутабельными делают типы, а не объекты. И константность тут мало чем помогает.

    V>Следовательно, гарантии происходят от того, кто эту ссылку передаёт во внешний мир — ведь только владелец данных "знает" характер своих данных.

    V>А выполняемый read-only код единообразен (например, банальное логирование), отсюда ортогональность кода к данным.
    Как и в явах-шарпах, разницы никакой.

    v>>> Но в типе SomeDictionary const index резко становится иммутабельным.

    V>·>Этот случай, кстати, поинтереснее. Т.к. это не голая структура, а есть куча всяких методов. И, внезапно, выясняется, что хоть и "резко", но уже не нахаляву — интерфейс SomeDictionary уже надо внимательно проектировать с разделением const/nonconst методов.
    V>Ес-но.
    V>Но это всё еще одно описание типа, где ты просто помечаешь read-only методы через const.
    Именно. А ещё засада в том, что const-методы часто ещё и требуют копи-пастной реализации (ага-ага, бинарник увеличивается), в отличие от интерфейсов, которые требуют только сигнатуру.

    V>У плюсовиков этот рефлекс на уровне мозжечка, бо является еще дополнительным документированием/аннотированием методов — профит! ))

    V>"Читать" такие типы потом проще.
    Субъективная вкусовщина.

    v>>> — ссылки на константные данные не гарантируют константность тех данных, они накладывают ограничения — позволяют использовать лишь иммутабельное АПИ объектов.

    V>·>константное, а не иммутабельное. Не жонглируй терминами.
    V>Никакого жонглирования, бо здесь речь не об неизменяемых данных, а об неизменяемой обработке данных, т.е. не вносящих в данные изменения.
    Твоя фраза должна была быть записана так: "ссылки на константные данные не гарантируют константность тех данных, они накладывают ограничения — позволяют использовать лишь константный АПИ объектов."
    И внезапно она становится скучной тавтологией. А твоей фривольностью подменять константность и иммутабельность на ходу в случайных местах — ты игнорируешь важное отличие между этими двумя терминами.

    V>Просто не надо складывать в кучу неизменяемые данные и алгоритмы, не изменяющие даные.

    V>(просил уже)
    А я просил не путать иммутабельность и константность.

    v>>> Как именно данные случаются неизменяемыми — да как угодно.

    v>>> Можно и безо-всяких const, record, final и прочих приблуд, достаточно того, чтобы в момент работы таких алгоритмов данные никто не изменял.
    V>·>Гарантию "никто не изменял" компилятор может дать лишь для иммутабельных типов.
    V>Это всё до некоторой степени, пока не пошли хаки, например, через реинтерпретацию памяти или рефлексию.
    Или уж сразу — отвёрткой в работающией материнке поковыряться....

    V>Лишь малое кол-во языков способно обеспечить доказуемость корректности своего кода.

    V>И ведь не просто так эти языки нифига не мейнстримовые?
    Ну вот хотя бы прогресс. Раньше ты утверждал, что есть гарантии. Ладно, что хоть согласился, что их на самом деле-то нет.

    v>>> Тут мы рассуждаем лишь о том, как защититься от случайного изменения невнимательным программистом данных, которые мы хотим рассматривать как иммутабельные.

    V>·>Так это константность называется, а не иммутабельность, опять термины поменяешь.
    V>Разве?
    V>

    V>Неизменяемым (англ. immutable) называется объект, состояние которого не может быть изменено после создания.

    селёдка — это рыба с хвостом.
    V>

    V>В языках программирования C, C++, C# и D const является квалификатором типа: ключевое слово применяется к типу данных, показывая, что данные константны (неизменяемы).

    Сёмга — это рыба с хвостом.
    Э. И? Из этого ты делаешь какой вывод? Что сёмга — это как селёдка?

    Похоже это русская вики. Там под словом "неизменяемый" неясно что понимается в каком контексте. Разберись по нормальным докам, лучше англоязычным.

    V>Если бы ключевое слово было не const, а immutable — тебе было бы легче? ))

    Ты не поверишь, но в том же D — есть оба квалификатора! Вот изучи зачем их там два и чем они отличаются, доку найдёшь, надеюсь.

    V>·>Если же прекратить черри-пикать факты, то надо рассуждать не лишь о том, что тебе по душе, но и об остальных аспектах, и ещё порассуждать о том не как "хотим рассматривать", а как иметь иммутабельность с гарантией компилятора.

    V>Гарантии в любом случае недоказуемы в обсуждаемых языках.
    В рекордах — данные гарантированно иммутабельны, по спеке языка. Но это не столь важно. Суть в том, что плюсы ничем не лучше по гарантиям других яп, хоть ты и обещал.

    V>В джаве можно допустить ошибку — изменив данные через некий метод интерфейса, который (интерфейс) согласно прикладной семантики должен был давать read-only view.

    В т.ч. и поэтому ввели рекорды.

    V>В плюсах можно забыть приписать полю const и однажды наступить в это, и т.д. до бесконечности.

    V>Более конструктивно будет обсуждать такой вариант, где программист выразил свои намерения верно и обеспечил "железобетонные гарантии".
    V>(которые всё-равно обходятся через хаки и в джаве, и в плюсах, но мы об этом скромно умалчиваем, бгг).
    Хаки можно запретить, по крайней мере в яве. (рефлексия отключается, модули запираются, етс).

    V>В этих вариантах останется обсуждать лишь выразительность (т.е. трудоёмкость готового решения) и ничего более.

    Именно, что остаётся обсуждать субъективныые эмоции. Но обсуждение было начато с утверждения, что эта константность нужна и важна и без неё жить невозможно в других яп, замены никакой.

    V>·>Не очень понял, что ты имеешь в виду перетянулы в шарп?

    V>В шарпе появились константные ссылки — "readonly ref", или кратко "in" для параметров (применяется для value-типов и для переменных-ссылок на GC-типы), а так же полные аналоги const-методов из плюсов — это "readonly" методы у value-типов.
    V>Всё вместе служит той же цели — выразительности кода при достижении тех или иных гарантий.
    Ясно. Надо почитать... Вполне верю, что идею константности можно довести до ума... но в том виде в каком она есть в плюсах — по-моему так себе...

    v>>> Еще как подмножество.

    V>·>Я привёл явный пример когда это не так.
    V>Не видел.
    V>И оно не может быть "не так" согласно определению иммутабельности и семантики кода, получающего read-only доступ к данным.
    Если ты напишешь код, обеспечивающий read-only, и код обеспечивающий иммутабельность — это будет разный код.

    v>>> Наоборот, упрощение, бо комбинаторный подход позволяет упростить базу — меньше писать.

    V>·>Даже по количеству буковок не сильно отличается.
    V>Не скажи.))
    V>Я привёл примёр read-only view на шарпе (на джаве можно аналогично, разве что +1 к косвенности), а в плюсах достаточно было простого ключевого слова const безо всей этой возни.
    Это ты яблоки с апельсинами сравнил. В том же шарпе уже есть ReadOnlyDictionary, тоже никакой возни.

    V>·>Я уже об этом упоминал. Нет никакого утяжеления. Интерфейсы в яве практически бесплатны.

    V>Вранье. ))
    V>Интерфейсы в джаве намного тяжелее прямых методов.
    V>Бесплатны они только если компилятор или JIT "видят" жизненный цикл ссылки — тогда может заменить вызов метода через интерфейс прямым вызовом.
    Нет. Там ставится uncommon trap. А то и совсем, если у интерфейса ровно одна загруженная реализация — оно его девиртуализует и инлайнит.

    V>·>Не экономит она труд.

    V>Выше пример, который не нужен в плюсах.
    В шарпах и этого не нужно писать. Труда ещё меньше.

    V>·>Насчёт размера тут тоже сложно всё. Неясно как можно адекватно сравнивать бинари плюсов и явы... слишком много нюансов.

    V>Надо сравнивать бинари в рамках одной техонлогии.
    V>Например, можно сравнивать бинари в плюсах при применении подхода джавы vs родного плюсового подхода.
    V>Или можно сравнивать бинари в шарпе, где доступны оба подхода для value-типов.
    В зависимости от способа сравнения можно получить противоположные результаты.

    V>В любом случае, лишний код есть лишний код.

    Так отличие может быть лишь в наличии интерфейса. Интерфейс — это просто список методов. И всё.

    V>·>Если я правильно помню, то это аналог final-поля, который был в java с рождения.

    V>Это изначально применительно к полям объектов.
    V>Затем readonly стало можно применять к аргументам методов и возвращаемым значениям.
    V>Затем через readonly стало можно помечать методы, где этот метод не может изменять внутренние поля — компилятор не даст.
    Ясно, возможно. Может когда-то и плюсы до ума доведут.

    v>>> Вплоть до того, что даже в иммутабельных сценариях в джаве редко кто заморачивается с внутренней гарантией этой иммутабельности.

    V>·>Не понимаю что ты понимаешь под сложностью.
    V>Лишний код.
    V>Тот же твой Defensive copying как малая часть этой сложности.
    V>Например, в дотнете достаточно передавать DateTime по значению или по константной ссылке, а в джаве надо делать GC-копию объекта на каждый чих.
    Уже давным давно в джаве сделали иммутабельное дату-время, а до этого были сторонние либы. Этой проблемы больше нет.

    V>Да там уже просто рука устаёт всё это внимательно описывать. ))

    Это вопрос конкретного дизайна конкретного АПИ. Да, можно накрутить сложности на пустом месте. Старый дизайн datetime api не пнул только ленивый, там было дохрена проблем, первый блин комом. Какой-то присущей сложности нет.
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Отредактировано 05.09.2023 11:28 · . Предыдущая версия .
    Re[92]: Когда это наконец станет defined behavior?
    От: vdimas Россия  
    Дата: 19.02.24 18:49
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>И вот тут я опять подозреваю, что ты нарочно флейм разводишь и цирк устраиваешь. Я попросил продемонстрировать "пример кода как обеспечить иммутабельность", а ты мне вываливаешь ReadOnlyDictionary, как нарочно мешаешь всё в кучу: кручу, верчу, запутать хочу.


    Именно иммутабельность я и продемонстрировал.


    ·>Или ты вообще невдупляешь что такое иммутабельность.


    Это "неизменяемость" по-русски.
    А что конкретно ты подразумеваешь под иммутабельностью — тут я уже ХЗ.
    Это уже какая-то нубская эзотерика попёрла — попытка наградить известные слова неизвестным смыслом.

    В программировании об иммутабельности данных говорят исключительно и только в связке с классами алгоритмов над неизменяемыми данными, бо сама по себе иммутальность и нафик никому не сдалась.

    Ты лишь демонстрируешь полнейшее непонимание этого, снова и снова цеплясь к самим данным, а не их прикладной роли и обрабатывающими их алгоритмами.
    Выжираешь своей несообразительностью терпение, бо все условия для корректной работы таких алгоритмов над неизменяемыми данными я соблюл.


    ·>Если так, то почитай доку .NET чем отличаются IImmutableDictionary и IReadOnlyDictionary.


    ЧТД "почитай доку".
    Оба интерфейса являются прикладными с т.з. компилятора, т.е. никаких гарантий не дают.
    Гарантии там сугубо вербальные, "в документации" (С), и могут быть нарушены в реализации интерфейсов аж бегом (преднамеренно или нет), бо компилятор умывает руки.

    Учитывая, что процитированное замечание я уже делал:

    В плюсах ведь доступен подход джавы, но это ж издевательство над психикой, поэтому никто так не делает.

    ... я делаю вывод о низком уровне сообразительности собеседника.

    Ты и сам должен понимать процитированное, что Джава крайне бедна, это один из самых паскуднейших языков современного мейнстрима (хуже был только Objective-C, но уже почти полностью заменён Свифтом и чистыми плюсами) и если что-то можно сделать в Джаве, то это можно сделать почти в любом ЯП. Тебе показали альтернативные в разы более выразительные ср-ва для достижения тех же целей — но ты оказался не в состоянии их понять.

    Помнишь, я уже попросил тебя реализацию словаря или приоритетной очереди на джавовских рекордах?
    В этом месте умный собеседник резко бы осознал, что дико загоняет, прикинулся бы ветошью и не отсвечивал, бо экономия на автоматическом описании типов там вышла бы ничтожной в сравнении со всем остальным необходимым объемом работ.
    А тупишь и тупишь, в попытках оправдать милое сердцу убожество.
    Ты ведь для этого пишешь с анонимного акка, чтобы не стыдно было, верно?
    Re[82]: Когда это наконец станет defined behavior?
    От: vdimas Россия  
    Дата: 19.02.24 18:51
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>Этот сценарий может возникнуть не только вокруг константности, а вообще везде. В C++ подстелили соломку, взяв легаси от C, а интерфейсы могут покрыть любую семантику.


    Но не дать никаких гарантий, которые ты так настойчиво требуешь от коллег.
    Это уже откровенная глупость выходит ))
    Re[93]: Когда это наконец станет defined behavior?
    От: · Великобритания  
    Дата: 20.02.24 00:15
    Оценка: :)
    Здравствуйте, vdimas, Вы писали:

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


    V>·>И вот тут я опять подозреваю, что ты нарочно флейм разводишь и цирк устраиваешь. Я попросил продемонстрировать "пример кода как обеспечить иммутабельность", а ты мне вываливаешь ReadOnlyDictionary, как нарочно мешаешь всё в кучу: кручу, верчу, запутать хочу.

    V>Именно иммутабельность я и продемонстрировал.
    Ты продемонстрировал readonly-view. Иммутабельности тут нет. В С++ иммутабельности тоже нигде нет (в лучшем случае для примитивов). Есть только readonly. В Java есть иммутабельность в виде record.

    V>·>Или ты вообще невдупляешь что такое иммутабельность.

    V>Это "неизменяемость" по-русски.
    Пример для совсем тупых: "/proc/uptime" — является read-only файлом. Он иммутабельный?
    Разберись чем отличается "неизменяемость" от "доступ только для чтения". Когда разберёшься, приходи.
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Отредактировано 20.02.2024 0:17 · . Предыдущая версия .
    Re[94]: Когда это наконец станет defined behavior?
    От: vdimas Россия  
    Дата: 20.02.24 11:31
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>Ты продемонстрировал readonly-view. Иммутабельности тут нет. В С++ иммутабельности тоже нигде нет (в лучшем случае для примитивов). Есть только readonly.


    У "неизменяемости" может быть сколько угодно синонимов и разных ключевых слов в разных ЯП — const, readonly, final и т.д.


    ·>Разберись чем отличается "неизменяемость" от "доступ только для чтения".


    Всё-таки эзотерика? ))
    Хорошо, что ты прилюдно признался.
    В угол, на гречку!

    Тебе уже говорилось, где у тебя каша в голове — надо рассуждать в терминах алгоримов над неизменяемыми данными, а не просто о самих таких данных.


    ·>Пример для совсем тупых: "/proc/uptime" — является read-only файлом. Он иммутабельный?


    Это пример от тупых, ведь они понятия не имеют, как устроен этот файл.
    Вполне может быть так, что на иммутабельных типах данных унутре, что почти всегда и происходит в тех же lock-free реализациях, когда ширина типа данных больше ширины слова — тогда значением оперируют по ссылке, которую (ссылку) подменяют в безблокировочной манере, но по самой ссылке находятся неизменяемые/иммутабельные данные.

    Твой "/proc/uptime" — это может быть лишь интерфейсом к таким данным. ))

    В любом случае, неизменяемость данных означает init-only характер оперирования данными, и как ты собрался "доказать", что это не так в случае "/proc/uptime"?
    Опять поторопился и опять облажался?


    ·>Когда разберёшься, приходи.


    Сказал чел, который сообщением выше утверждал про связь иммутабельности и интерфейсов, чем тоже облажался.
    (ты уже второй, кто попадается на этом, бгг)

    Вы оба рассматривали имеющиеся интерфейсы, чесали репу и пытались что-то эдакое выудить из увиденного, но, в отсутствии жесткой базы на уровне мозжечка, рождаете лишь хаотический бред.

    1. Интерфейсы не имеют к иммутабельности никакого отношения, а служат для чего и придуманы в ООП — это ср-во абстрагирования для целей последующего обобщения.

    2. Разница набора операций в IReadOnlyXXX и IImmutableXXX показывает лишь озвученную разницу — в уровне абстрагирования/обобщения, соотв. IReadOnlyXXX может быть использован в более общем коде, а IImmutableXXX в более специализированном. Плюс, не стоит забывать, что интерфейсы — это совокупность операций, представляющих собой "тип" в ООП-ЯП (см второй абзац этого поста).

    3. Набор операций IReadOnlyXXX является подмножеством IImmutableXXX (ты даже с этим пытался спорить, не посмотрев на граф наследования), но оба интерфейса к иммутабельности не имеют никакого отношения, когда речь заходит о гарантиях. Бо интерфейсы (абстрактные классы) в классическом ООП используют не для гарантий, а как единственный доступный механизм построения и оперирования абстракциями. Остальное — спекуляции полуграмотных полупрограммистов из цикла "слышал звон".

    4. Неизменяемость ортогональна любому выбранному уровню абстракции, прекрасно умеет жить как без абстракций, так и сосуществовать с ними.

    5. Любые гарантии/ограничения, которые предоставляет ЯП для решения тех или иных классов задач, намного лучше отсутствия таких ср-в.

    Весь этот спор — это просто тебя и еще одного громкого чела душила жаба, что в жабке нет адекватных ср-в для решения задач над иммутабельными типами данных (у второго дотнет чаще чешется). Вы тупо беситесь в попытках оправдать любимые ЯП, увлекаетесь и не проверяете свой бред на соответствие хотя бы определениям и здравому смыслу.

    Но я тебя слегка утешу — в жабке есть GC, который является достаточно эффективной базой для реализации большого класса алгоритмов над неизменяемыми данными.

    Поэтому, если бы ты хоть что-то понимал в таких алгоритмах, тебе достаточно было ткнуть в отсутствие GC в C++ и одновременно в происходящее во многих таких алгоритмах (например, алгоритмы над иммутабельными сбалансированными деревьями и вообще над иммутабельными версионными графами, известными еще со времён самого первого Лиспа), где наличие GC упрощает реализацию таких алгоритмов.
    Отредактировано 20.02.2024 13:56 vdimas . Предыдущая версия . Еще …
    Отредактировано 20.02.2024 13:56 vdimas . Предыдущая версия .
    Отредактировано 20.02.2024 13:54 vdimas . Предыдущая версия .
    Отредактировано 20.02.2024 13:54 vdimas . Предыдущая версия .
    Отредактировано 20.02.2024 11:34 vdimas . Предыдущая версия .
    Re[11]: Когда это наконец станет defined behavior?
    От: Кодт Россия  
    Дата: 21.02.24 10:25
    Оценка:
    Здравствуйте, T4r4sB, Вы писали:

    TB>Ну уб получается.


    У, но другое. Не undefined, а unspecified.
    Вход-выход в функцию (а с c++17 даже передача каждого отдельного аргумента) создаёт точки следования, поэтому есть какие-то базовые гарантии о неповреждённых значениях.
    Но вот порядок вызовов функции и обращения к переменной — произвольный.

    https://en.cppreference.com/w/cpp/language/eval_order

    int a = 1;
    
    inline int g() { return ++a; }
    
    int f1a() { return g()*100 +  g() *10 +   a  ; }  // unspecified
    int f1b() { return  a *100 +   a  *10 +   a  ; }  // unspecified
    int f1c() { return  a *100 +   a  *10 +  g() ; }  // unspecified
    int f1c() { return  a *100 +   a  *10 + (++a); }  // UNDEFINED
    
    int f2a() { return g()*100 +  g() *10 +  g() ; }  // unspecified
    int f2b() { return g()*100 + (++a)*10 +  g() ; }  // unspecified
    int f2c() { return g()*100 + (++a)*10 + (++a); }  // UNDEFINED
    Перекуём баги на фичи!
    Re[93]: Когда это наконец станет defined behavior?
    От: Кодт Россия  
    Дата: 21.02.24 10:28
    Оценка:
    Здравствуйте, vdimas, Вы писали:

    V>Именно иммутабельность я и продемонстрировал.


    и некропостинг...
    Перекуём баги на фичи!
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.