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

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

Страниц: 1 ... 4 5 [6]   Вниз
  Печать  
Автор Тема: Итераторы  (Прочитано 32161 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #75 : Апрель 23, 2021, 17:40 »

..что мешает тогда создать временный вектор ..
Угрызения совести Улыбающийся Все-таки это говнокод

Ну, это скажем так, простое решение малой кровью (без лишних классов-итераторов-шаблонов).

Но лучшим решением было бы void processItem(CData& item).
Записан

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 не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #76 : Апрель 24, 2021, 06:45 »

Да, совсем забыл привести свое решение. Начнем с этого
Код
C++ (Qt)
void CBigClass::SomeMethod( bool useSelection )
{
 ..
 int limit = useSelection ? mSelection.size() : mData.size();
 auto dataIt = mData.begin();  
 auto selIt = mSelection.begin();  
 for (int i = 0; i < limit; ++i) {
   CData * dataPtr;
   if (useSelection) {
      dataPtr = *selIt;
      ++selIt;
   }
   else {
      dataPtr = &(*dataIt);
      ++dataIt;
   }
 
  ...
 }
}
 
Все тут вполне хорошо, пусть десяток лишних строк, от этого не умирают. Чтобы схлопнуть надо попрятать итераторные кишки в класс
Код:
void CBigClass::SomeMethod( bool useSelection ) 
{
  ..
  CDataIt it(*this, useSelection);
  while (it.HasNext()) {
    CData & data = it.GetNext();
    ....
}
И пусть Has/GetNext разбираются какой итератор продвигать и как вернуть ссылку. Правда как оформить в стиле плюсов (for auto & data : it) я не знаю Улыбающийся
Записан
AkonResumed
Чайник
*
Offline Offline

Сообщений: 81


Просмотр профиля
« Ответ #77 : Апрель 24, 2021, 12:02 »

С вашего позволения вернусь к обозначенной проблеме UB reinterpret_cast'a. Изначальный вариант:
Код:
QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() 
{
static_assert(sizeof(CData*) == sizeof(std::reference_wrapper<CData>));
return reinterpret_cast<QSet<std::reference_wrapper<CData>>&>(mSelection);
}
полагаю, можно сделать полностью безопасным вот так:
Код:
QSet<std::reference_wrapper<CData>>& mSelectionAsRefs()
{
static_assert(sizeof(CData*) == sizeof(std::reference_wrapper<CData>));

QSet<CData*>* src = &mSelection;
QSet<std::reference_wrapper<CData>>* alias;

std::memcpy(&alias, &src, sizeof(alias));  // starts lifetime of alias as QSet<CData*>*
return *alias;
}
Фишка этого приема в том, что memcpy() дает понять компилятору, что alias стартует как тип src, т.е. QSet<CData*>*.

Или эквивалент (м.б. более понятный):
Код:
QSet<std::reference_wrapper<CData>>& mSelectionAsRefs()
{
static_assert(sizeof(CData*) == sizeof(std::reference_wrapper<CData>));

QSet<CData*>* src = &mSelection;
void* alias;

std::memcpy(&alias, &src, sizeof(alias));  // starts lifetime of alias as QSet<CData*>*
return *static_cast<QSet<std::reference_wrapper<CData>>*>(alias);
}
Здесь alias прямо декларируется как void* - тип, полностью совместимый с любым указателем (альтернативно, можно char* alias[sizeof(src)]), и далее используется static_cast.

Естественно, после оптимизации новый вариант относительно старого не должен иметь никаких дополнителных расходов.

Остается только одна потенциальная проблема - возможная специализация контейнера для указателей. В принципе, ее легко решить, если сделать свою специализацию контейнера для std::reference_wrapper<CData>, которая будет иметь битовую идентичность с контейнером CData*. Но это лениво (много букв).
« Последнее редактирование: Апрель 24, 2021, 12:04 от AkonResumed » Записан
AkonResumed
Чайник
*
Offline Offline

Сообщений: 81


Просмотр профиля
« Ответ #78 : Апрель 24, 2021, 14:28 »

Да, и в С++20 это делается уже так (std::bit_cast):
Код:
QSet<std::reference_wrapper<CData>>& mSelectionAsRefs() 
{
static_assert(sizeof(CData*) == sizeof(std::reference_wrapper<CData>));
return std::bit_cast<QSet<std::reference_wrapper<CData>>&>(mSelection);
}
Т.е. дали заднюю со своим strict type aliasing.

Еще вариант (ИМХО, в общем случае малоприемлемый) - выключить strict type aliasing опцией компилятора. Ядро Линукса, например, компилится с -fno-strict-aliasing, а там, как можно догадаться, еще те любители реинтерпретации.
« Последнее редактирование: Апрель 24, 2021, 21:19 от AkonResumed » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #79 : Апрель 24, 2021, 14:52 »

Фишка этого приема в том, что memcpy() дает понять компилятору, что alias стартует как тип src, т.е. QSet<CData*>*.
По-моему memcpy просто "соответствует своему названию" - и все. Каким образом он может что-то "дать понять" Непонимающий. Также что значит "стартует как"   Непонимающий

Ну размеры эл-тов равны - и все, приводим, не понял чего Вы еще опасаетесь? Мифических хвостов? В общем - поясните
Записан
AkonResumed
Чайник
*
Offline Offline

Сообщений: 81


Просмотр профиля
« Ответ #80 : Апрель 24, 2021, 15:46 »

Цитировать
"стартует как"
Код:
void* p;          // declaration
p = new int(5);   // p begins its lifetime with dynamic type int*

Вот здесь по сути вопроса изложено четко и с примером: https://en.cppreference.com/w/cpp/string/byte/memcpy
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #81 : Апрель 24, 2021, 16:58 »

Код:
void* p;          // declaration
p = new int(5);   // p begins its lifetime with dynamic type int*

Вот здесь по сути вопроса изложено четко и с примером: https://en.cppreference.com/w/cpp/string/byte/memcpy
Прочел дважды, ничего нового не почерпнул Улыбающийся Про "lifetime" там ничего нет. Да и откуда оно возьмется для объекта созданного в куче, сам распределил - сам и удаляй
Записан
AkonResumed
Чайник
*
Offline Offline

Сообщений: 81


Просмотр профиля
« Ответ #82 : Апрель 24, 2021, 21:57 »

Те же яйца, только в профиль:
Код:
int i;
void* p;  // declaration
p = &i;  // p begins its lifetime with dynamic type int*

memcpy: Notes

std::memcpy may be used to **implicitly create** objects in the destination buffer.
...
Where strict aliasing prohibits examining the same memory as values of two different types, std::memcpy may be used to convert the values.

И далее почитать по ссылке https://en.cppreference.com/w/cpp/language/object#Object_creation что такое объекты и как они создаются.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #83 : Апрель 25, 2021, 08:19 »

Те же яйца, только в профиль:
Код:
int i;
void* p;  // declaration
p = &i;  // p begins its lifetime with dynamic type int*
И что? Ну присвоили void * адрес чего-то, на здоровье. Но никаких "вытекающих" из этого нет, поведение p будет точно таким же как и при любой другой его установке. Неявное создание с помощью memcpy - ну да, если объект "тривиально копируемый" (как сейчас говорят), то можно и так, хотя времена таких трюков давно прошли, ну разве в контейнере чтобы пошустрее.

И тот reinterpret_cast, нафиг он нужен? Тем более memcpy. Да просто так
Код
C++ (Qt)
using CDataRef = std::reference_wrapper<CData>;
QSet<CDataRef>& SelectionAsRefs( void )
{
static_assert(sizeof(CData*) == sizeof(CDataRef));
return *(QSet<CDataRef> *) &mSelection;
}
 
И вся любовь.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #84 : Апрель 25, 2021, 09:02 »

И тот reinterpret_cast, нафиг он нужен? Тем более memcpy. Да просто так
Код
C++ (Qt)
using CDataRef = std::reference_wrapper<CData>;
QSet<CDataRef>& SelectionAsRefs( void )
{
static_assert(sizeof(CData*) == sizeof(CDataRef));
return *(QSet<CDataRef> *) &mSelection;
}
 
И вся любовь.
Точно.
А придурки из комитета все какие то касты придумывают, то static_cast, то reinterpret_cast, сейчас bit_cast придумали. Нечем им заняться. Улыбающийся
Зачем? Если можно сишным кастануть и вся любовь. Улыбающийся
Записан
AkonResumed
Чайник
*
Offline Offline

Сообщений: 81


Просмотр профиля
« Ответ #85 : Апрель 25, 2021, 09:59 »

Да, любовь - странная штука:
Код:
#include <QSet>
#include <iostream>

using namespace std;

typedef int CData;
using CDataRef = reference_wrapper<CData>;

QSet<CData*>* mSelection = new QSet<CData*>;

QSet<CDataRef>*& SelectionAsRefs( void )
{
static_assert(sizeof(CData*) == sizeof(CDataRef));
return *(QSet<CDataRef> **) &mSelection;
}

static QSet<CData*>* makeUB(QSet<CData*>** src, QSet<CDataRef>** alias)
{
static QSet<CData*> data = { new CData };  // set with one element

*src = &data;
*alias = nullptr;

return *src;  // what will be there: &data or nullptr?
}

int main(int, char *[])
{
mSelection = makeUB(&mSelection, &SelectionAsRefs());
std::cout << (!mSelection ? "OK" : "UB") << std::endl;
}
Этот код дает UB при -O2. Я вынужден был перейти от QSet<CData*> к QSet<CData*>*. Непосредственно тип QSet<CData*> UB не дает. Полагаю, что давал бы, если бы в нем был "простой" конструктор.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #86 : Апрель 25, 2021, 10:41 »

Этот код дает UB при -O2.
С перекрытием полей много чего "дают" (правда никто не хочет "получать"). Как бы Вы ни крутили, смысл один - вот эта "ячейка памяти" должна трактоваться как "нужный тип", без всяких изменений. Сишный каст это делает (в крайнем случае через void *) - ну и слава богу.

Разве Вы не чувствуете что "порог сложности" давно уже пройден? Не нужно решение такой ценой, даже если оно 100% корректно.

И вообще, чего Вы уперлись в эту мелочь? Вот сегодня создал тоже интересную темку. А какая шикарная тема про интеграцию скриптов. Был бы умный человек, а о чем с ним поговорить - я найду, не переживайте  Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #87 : Апрель 25, 2021, 11:05 »

Разве Вы не чувствуете что "порог сложности" давно уже пройден? Не нужно решение такой ценой, даже если оно 100% корректно.
Использование итераторов полностью разрывает порог сложности. И цена решения непомерна. Улыбающийся

Был бы умный человек, а о чем с ним поговорить - я найду, не переживайте  Улыбающийся
Потому что на целом форуме желающих почти не осталось. Улыбающийся
Записан
Страниц: 1 ... 4 5 [6]   Вверх
  Печать  
 
Перейти в:  


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