Russian Qt Forum
Ноябрь 22, 2024, 01:14 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: UB или нет?  (Прочитано 9533 раз)
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« : Июль 19, 2018, 20:41 »

Код QString:

Код
C++ (Qt)
const ushort *QString::utf16() const
{
   if (IS_RAW_DATA(d)) {
       // ensure '\0'-termination for ::fromRawData strings
       const_cast<QString*>(this)->reallocData(uint(d->size) + 1u);
   }
   return d->data();
}

См. https://code.woboq.org/qt5/qtbase/src/corelib/tools/qstring.cpp.html#_ZN7QString11reallocDataEjb

reallocData() модифицирует член класса d. А что если объект QString - константный? Модификация константного объекта или его членов с использованием const_cast<T*> - UB. Так я всегда думал... Или нет?
« Последнее редактирование: Июль 19, 2018, 20:43 от Alex Custov » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Июль 19, 2018, 20:50 »

Нет, это не UB.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #2 : Июль 19, 2018, 20:55 »

Нет, это не UB.

Спасибо за ответ Веселый Почему?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Июль 19, 2018, 21:03 »

Ты можешь спокойно снимать константность, никто тебя за это не накажет. Кроме другого разработчика, конечно. Улыбающийся. А есть еще mutable мемберы.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Июль 19, 2018, 21:07 »

А если строев в RO памяти?
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #5 : Июль 19, 2018, 21:09 »

Ты можешь спокойно снимать константность, никто тебя за это не накажет. Кроме другого разработчика, конечно. Улыбающийся. А есть еще mutable мемберы.

член d - не mutable. https://en.cppreference.com/w/cpp/language/const_cast говорит:

Цитировать
const_cast makes it possible to form a reference or pointer to non-const type that is actually referring to a const object or a reference or pointer to non-volatile type that is actually referring to a volatile object. 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.

Код
C++ (Qt)
struct type {
   int i;
 
   type(): i(3) {}
 
   void f(int v) const {
       // this->i = v;                 // compile error: this is a pointer to const
       const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
   }
};
 
type t; // if this was const type t, then t.f(4) would be undefined behavior
t.f(4);
 
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Июль 19, 2018, 22:59 »

Ну, в Qt это нормальная практика кастить приватные мемберы к const_cast в константных методах.

Модифицируется то не QString, а d-пойнтер! А он вроде не константный.
Записан

ArchLinux x86_64 / Win10 64 bit
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #7 : Июль 19, 2018, 23:19 »

Модифицируется то не QString, а d-пойнтер! А он вроде не константный.

d-pointer - это мембер класса. Компилятор засунет весь константный объект QString в RO секцию - и что ты там будешь модифицировать? См. мой предыдущий комент с выдержками из cppreference.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июль 20, 2018, 09:18 »

reallocData() модифицирует член класса d. А что если объект QString - константный? Модификация константного объекта или его членов с использованием const_cast<T*> - UB. Так я всегда думал... Или нет?
Ну хорошо, допустим мы "не писяем и не какаем" (все только легально) - а что делать в данном случае? Метод utf16() должен возвращать данные с нуль-терминатором - ну вот "так надо", но "сырая" строка его не имеет. Давайте utf16() делать НЕ константным! (др предложений никогда не слыхал). Ну так это еще хуже, вся константность развалится по цепочке.

Кстати не вижу случая когда IS_RAW_DATA сработает. Методы setRawData/fromRawData (вроде бы позволяют строке ссылаться на внешние данные) почему-то упорно их копируют
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Июль 20, 2018, 11:34 »

Да, подумав ещё, такая строка не может лежать в ро-секции, чтобы её инициализировать, надо вызвать fromRawData, который не constexpr, а значит будет вызван в рнтайме, а значит аллоцирует контрольный блок и запишет в d. Т.е. этот d обязан лежать в rw памяти.
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #10 : Июль 20, 2018, 12:34 »

Да, подумав ещё, такая строка не может лежать в ро-секции, чтобы её инициализировать, надо вызвать fromRawData, который не constexpr, а значит будет вызван в рнтайме, а значит аллоцирует контрольный блок и запишет в d. Т.е. этот d обязан лежать в rw памяти.

Почему?

Код
C++ (Qt)
const QString str = QString::fromRawData(unicode, size);

Разве str за кулисами будет лежать в rw?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #11 : Июль 20, 2018, 14:20 »

Почему?

Код
C++ (Qt)
const QString str = QString::fromRawData(unicode, size);

Разве str за кулисами будет лежать в rw?

Да, конструктор нетривиальный нужен.
Всё, что не может быть сделано на этапе компиляции, делается в рантайме. В данном случае при загрузке бинаря вызывается функция fromRawData, аллоцируется контрольный блок, который надо записать в d.
Это возможно только если d не в RO.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Июль 21, 2018, 09:24 »

А откуда эта легенда про "RO"?  Насколько я понял Read Only (Memory). И зачем так упорно хвататься за этот частный случай? Отловить дефекты const_cast можно напр так
Код
C++ (Qt)
static const QChar data[4] = { 0x0055, 0x006e, 0x10e3, 0x03a3 };
QString str = QString::fromRawData(data, 4);
const QChar * p0 = str.constData();
const ushort * utf = str.utf16();
const QChar * p1 = str.constData();
qDebug() << data << p0 << p1 << (p0 == p1);
 
Причем константный data() (вместо constData()) не катит, он также скопирует, причем даже не прибегая к const_cast, а с наглой мордой: reinterpret_cast

Поэтому формально да, UB. А по сути, ф-ционалу - верное решение. Хотели использовать "внешние" данные - получите, пусть и с геморроем
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #13 : Июль 21, 2018, 21:31 »

А откуда эта легенда про "RO"?  Насколько я понял Read Only (Memory). И зачем так упорно хвататься за этот частный случай? Отловить дефекты const_cast можно напр так
Код
C++ (Qt)
static const QChar data[4] = { 0x0055, 0x006e, 0x10e3, 0x03a3 };
QString str = QString::fromRawData(data, 4);
const QChar * p0 = str.constData();
const ushort * utf = str.utf16();
const QChar * p1 = str.constData();
qDebug() << data << p0 << p1 << (p0 == p1);
 
Причем константный data() (вместо constData()) не катит, он также скопирует, причем даже не прибегая к const_cast, а с наглой мордой: reinterpret_cast

Поэтому формально да, UB. А по сути, ф-ционалу - верное решение. Хотели использовать "внешние" данные - получите, пусть и с геморроем

Вы в курсе, что такое UB вообще? В данном случае UB нет, поведение странное, но четко определенное. Вот если бы при вызове utf16 ваша кошка рожала котенка - это было бы UB.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Июль 22, 2018, 05:59 »

Вы в курсе, что такое UB вообще? В данном случае UB нет, поведение странное, но четко определенное. Вот если бы при вызове utf16 ваша кошка рожала котенка - это было бы UB.
Да, если понимать UB буквально (undefined). Ну ТС трактует ширше, типа "некорректно" (с точки зрения  языка), почему бы и нет? В данном случае так и есть, никакое оно не "странное", а просто-напросто неверное, напр использующий p0 рухнет после вызова utf16 (объявленного как константный).

Кстати не очень понял а зачем копировать "внешние" данные при первом же шорохе, какая в этом необходимость? Не дороговато ли обходится "завершающий ноль" для QString::utf16. QString::data и др? Почему не прожить без него, size() есть
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.19 секунд. Запросов: 23.