Russian Qt Forum
Апрель 18, 2024, 20:38
Добро пожаловать,
Гость
. Пожалуйста,
войдите
или
зарегистрируйтесь
.
Вам не пришло
письмо с кодом активации?
1 час
1 день
1 неделя
1 месяц
Навсегда
Войти
Начало
Форум
WIKI (Вики)
FAQ
Помощь
Поиск
Войти
Регистрация
Russian Qt Forum
>
Forum
>
Программирование
>
С/C++
>
Итераторы
Страниц:
1
2
[
3
]
4
5
6
Вниз
« предыдущая тема
следующая тема »
Печать
Автор
Тема: Итераторы (Прочитано 26389 раз)
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #30 :
Апрель 20, 2021, 22:35 »
Цитировать
Там внутри могут быть всякие traits которые для разных типов разные.
Но в любом случае, даже если битовое представление одинаковое, это UB.
Могут, но это лишено практического смысла. Для контейнера важен только размер элемента (точнее, скажем "семантический размер", как в случае с bool), а сам элемнт, будь хоть POD, хоть класс с VMT - в плане хранения - все равно. Если обратное, то это уже не контейнер, а контейнер + еще что-то (т.е. bad design).
Цитировать
В чем проблема-то? Единственный валидный юзкейз reinterpret_cast между разными типами это каст к массиву байт (или void*) и обратно.
Компилятор знает что вон тот char buffer[] потенциально может алиаситься с вот этим указателем и сгенерит менее производительный код.
placement new как раз подпадает под это - буфер чаров может алиаситься (и делает это) с указателем на произвольный T.
А вот любые другие типы (например int* в double*) алиаситься не могут
Я к тому, что поинтер-алиасинг это не только про reinterpret_cast. Вот этот код дает UB (печатает -1 вместо ожидаемого 0) в обоих случаях (MinGW 8.3, O2):
Код:
#include <iostream>
int foo(float* f, int* i)
{
*i = -1;
*f = 0.0f;
return *i;
}
int main(int, char *[])
{
int i;
//i = foo(reinterpret_cast<float*>(&i), &i); // 1
i = foo(new(&i) float, &i); // 2
std::cout << i << std::endl;
}
А теперь вернусь в контекст нашей задачи - слегка модифицирую код на манер std::reference_wrapper, для упрощения я использовал просто структуру:
Код:
#include <iostream>
#if 0 // 0 - OK, 1 - UB
typedef float F;
#else
struct F
{
int i;
F(float v = 0.0f) { reinterpret_cast<float&>(i) = v; }
};
#endif
int foo(F* f, int* i)
{
*i = -1;
*f = 0.0f;
return *i;
}
int main(int, char *[])
{
int i;
//i = foo(reinterpret_cast<F*>(&i), &i); // 1
i = foo(new(&i) F(), &i); // 2
std::cout << i << std::endl;
}
При #if 0 UB больше нет в обоих случаях. #if 1 - это как в предыдущем случае с UB.
Почему больше нет UB? - сходу не найду - но еще вроде со всремен C++11 правил алиасинга если один из типов агрегатный и включает другой членом - то это не UB.
Итого:
Типы reference_wrapper<T> и Т* должны быть безопасны в плане reinerpret_cast, т.к. первый инкапсулирует второй как член, что следует из того, что sizeof(reference_wrapper<T>) == sizeof(Т*)т.е. reference_wrapper<T> никак не может быть реализован по-другому, кроме как инкапсулировать указатель и больше ничего.
«
Последнее редактирование: Апрель 20, 2021, 22:57 от AkonResumed
»
Записан
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #31 :
Апрель 20, 2021, 23:00 »
От-т! Опять я упустил внешний контейнер (QSet).
Авварон, по алиасингу вынужден с вами также согласиться. Друзья, спасибо!
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: Итераторы
«
Ответ #32 :
Апрель 21, 2021, 10:12 »
Цитата: AkonResumed от Апрель 20, 2021, 22:35
Код:
*i = -1;
*f = 0.0f;
Ну вообще-то компилятор имеет право выполнять эти операции в любом порядке, поэтому если адрес перекрывается, то рез-т не определен, тонкости ре-интерпретации здесь ни при чем.
Пример vector<bool> приводится так часто/неизменно, что скорее говорит о том что никаких других просто нет
С placement new как-то не уловил, неплохо бы пожевать. Спасибо
Цитата: AkonResumed от Апрель 20, 2021, 23:00
От-т! Опять я упустил внешний контейнер (QSet).
Типа "а вот возможен такой контейнер что будет иметь какие-нить traits - и тогда заклинит"? Может и да, но лично меня это совершенно не волнует. Я не собираюсь лепить врапперы всегда и везде, речь идет о конкретном случае в котором он весьма кстати. А объявить любой reinterpret_cast UB/хаком никакого ума не требует. Заметьте что чем больше человек говорит о корректности - тем меньше решений предлагает. Такой подход не конструктивен.
Цитата: AkonResumed link=topic=32938.msg244690#msg244690
Авварон, по алиасингу вынужден с вами также согласиться. Друзья, спасибо!
Возможно/предполагаю, Вы почувствовали что разбор этих тонкостей (или толстостей) отнимает слишком много времени, а работа-то стоит. Да, согласен
Записан
Old
Джедай : наставник для всех
Offline
Сообщений: 4349
Re: Итераторы
«
Ответ #33 :
Апрель 21, 2021, 10:21 »
Цитата: Igors от Апрель 21, 2021, 10:12
Может и да, но лично меня это совершенно не волнует. Я не собираюсь лепить врапперы всегда и везде, речь идет о конкретном случае в котором он весьма кстати.
Да вы можете это брать и использовать.
Дальнейшее обсуждения больше для разработчиков, что бы никто из них по неосторожности у себя не задействовал.
Записан
Racheengel
Джедай : наставник для всех
Offline
Сообщений: 2679
Я работал с дискетам 5.25 :(
Re: Итераторы
«
Ответ #34 :
Апрель 21, 2021, 10:36 »
Цитировать
Вот этот код дает UB (печатает -1 вместо ожидаемого 0)
Почему UB? Он и должен выводить -1.
В коде же явно написано "*i = -1", а i передаётся поинтером 1 в 1.
Другое дело, что такой код в продакшене никто использовать не будет.
Разве что как тест для компилятора.
Записан
What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.
COVID не волк, в лес не уйдёт
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #35 :
Апрель 21, 2021, 10:53 »
UB, потому что следом *f = 0.0f; зануляет туже самую область памяти. Так и происходит, но компилятор, при возврате в return *i; попросту не перезагружает значение из памяти, потому как считает, что f не может указывать на ту же ячеку, что и i, соответственно, она не может быть изменена через f. Для return *i; компилятор просто хардкодит 1 в eax/rax (регистр, через который идет возврат значения функции).
Записан
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #36 :
Апрель 21, 2021, 11:02 »
Да, и порядок выполнения операций здесь не при чем. Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык. UB возникает именно из-за оптимизатора и формального правила стандарта, которое он использует для оптимизации.
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: Итераторы
«
Ответ #37 :
Апрель 21, 2021, 11:23 »
Цитата: AkonResumed от Апрель 21, 2021, 11:02
Да, и порядок выполнения операций здесь не при чем. Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык. UB возникает именно из-за оптимизатора и формального правила стандарта, которое он использует для оптимизации.
Не уверен. Вот был интересный случай
Код
C++ (Qt)
float
Rand
(
uint32
&
seed
)
;
QVector3D vec
(
Rand
(
seed
)
,
Rand
(
seed
)
,
Rand
(
seed
)
)
;
Эта ошибка долго оставалась незамеченной, но когда перешел на шланг - тот выдал варнинт, молодец.
Конечно в в любом случае перекрывать адреса = ненужный поиск приключений. Вообще употребляемые здесь слова "продакшн", "разработка" и.т.п. - это просто "надувание щек", здесь обсуждается всего лишь мелкая деталь
Записан
Old
Джедай : наставник для всех
Offline
Сообщений: 4349
Re: Итераторы
«
Ответ #38 :
Апрель 21, 2021, 11:28 »
Цитата: Igors от Апрель 21, 2021, 11:23
Вообще употребляемые здесь слова "продакшн", "разработка" и.т.п. - это просто "надувание щек", здесь обсуждается всего лишь мелкая деталь
Боже, от вас слышать про надувание щек...
Записан
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #39 :
Апрель 21, 2021, 11:29 »
И как вы предполагали - какой Rand будет вызван первым - левый или правый?
Записан
AkonResumed
Чайник
Offline
Сообщений: 81
Re: Итераторы
«
Ответ #40 :
Апрель 21, 2021, 11:41 »
В этом контексте (порядка вычисления аргументов) частая ошибка, допускающая лик:
Код:
void foo(std::shared_ptr<MyClass> c, int x);
foo(std::shared_ptr<MyClass>(new MyClass), getXValue());
Записан
Авварон
Джедай : наставник для всех
Offline
Сообщений: 3258
Re: Итераторы
«
Ответ #41 :
Апрель 21, 2021, 11:47 »
Цитата: AkonResumed от Апрель 20, 2021, 22:35
Вот этот код дает UB (печатает -1 вместо ожидаемого 0) в обоих случаях (MinGW 8.3, O2):
Да, прикольно, не задумывался о том что placement new можно звать на unrelated типах.
Небось тоже где-то прописано что так делать нельзя (кроме char*/void*)
Записан
Авварон
Джедай : наставник для всех
Offline
Сообщений: 3258
Re: Итераторы
«
Ответ #42 :
Апрель 21, 2021, 11:52 »
Цитата: AkonResumed от Апрель 21, 2021, 11:29
И как вы предполагали - какой Rand будет вызван первым - левый или правый?
В 2ГИСе мы спрашивали похожую задачку
std::cout << f() << f() << f() << std::endl;
где f() имеет сайд-эффект (делает i++)
никто не решил (я в том числе)
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: Итераторы
«
Ответ #43 :
Апрель 21, 2021, 11:58 »
Цитата: AkonResumed от Апрель 21, 2021, 11:29
И как вы предполагали - какой Rand будет вызван первым - левый или правый?
Мне все равно (будет надо - посмотрю в отладчике), главное рез-т должен быть воспроизводимым при том же seed.
Цитата: AkonResumed от Апрель 21, 2021, 11:02
Порядок выполнения не нарушет видимый (ожидаемый) результат однопоточного исполнения. Это же императивный язык.
Это противоречит духу/идее "конвейера". Во всяком случае "распаковкой операндов" для последующих команд(ы) процессор занимается.
Цитата: Авварон от Апрель 21, 2021, 11:52
никто не решил (я в том числе)
Любая задача имеет по меньшей мере одно решение: снятие самой задачи/проблемы. Здесь оно и будет лучшим - не нужны такие заморочки.
Записан
Авварон
Джедай : наставник для всех
Offline
Сообщений: 3258
Re: Итераторы
«
Ответ #44 :
Апрель 21, 2021, 12:03 »
Цитата: Igors от Апрель 21, 2021, 11:58
Любая задача имеет по меньшей мере одно решение: снятие самой задачи/проблемы. Здесь оно и будет лучшим - не нужны такие заморочки.
Ну там задачи были разной сложности что позволяло оценить уровень кандидата. Полезно иметь задачу с подвохом ультимативной сложности. Если человек скажет какой-то один из возможных вариантов, то норм (там еще надо продраться сквозь код же), а если про точки следования вспомнит - ваще бох. Правда на моей памяти никто без подсказок не вспомнил, но это и не особо влияло.
Записан
Страниц:
1
2
[
3
]
4
5
6
Вверх
Печать
« предыдущая тема
следующая тема »
Перейти в:
Пожалуйста, выберите назначение:
-----------------------------
Qt
-----------------------------
=> Вопросы новичков
=> Уроки и статьи
=> Установка, сборка, отладка, тестирование
=> Общие вопросы
=> Пользовательский интерфейс (GUI)
=> Qt Quick
=> Model-View (MV)
=> Базы данных
=> Работа с сетью
=> Многопоточное программирование, процессы
=> Мультимедиа
=> 2D и 3D графика
=> OpenGL
=> Печать
=> Интернационализация, локализация
=> QSS
=> XML
=> Qt Script, QtWebKit
=> ActiveX
=> Qt Embedded
=> Дополнительные компоненты
=> Кладовая готовых решений
=> Вклад сообщества в Qt
=> Qt-инструментарий
-----------------------------
Программирование
-----------------------------
=> Общий
=> С/C++
=> Python
=> Алгоритмы
=> Базы данных
=> Разработка игр
-----------------------------
Компиляторы и платформы
-----------------------------
=> Linux
=> Windows
=> Mac OS X
=> Компиляторы
===> Visual C++
-----------------------------
Разное
-----------------------------
=> Новости
===> Новости Qt сообщества
===> Новости IT сферы
=> Говорилка
=> Юмор
=> Объявления
Загружается...