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

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

Страниц: 1 ... 5 6 [7] 8 9   Вниз
  Печать  
Автор Тема: C++ Object Token Library  (Прочитано 58963 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #90 : Февраль 12, 2020, 10:51 »

Вот ИМЕННО ПОЭТОМУ нельзя использовать голые указатели.
Не понял этого акцента

..либо делаете все на голых указателях (и страдаете).
Да, но от вумных (вернее от их беспросветной тупости) я страдаю гораздо больше Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #91 : Февраль 12, 2020, 11:13 »

Выходит безымянный юник созданный make_unique убился, но heap_unique перехватил данные (строку). А если так
Код:
auto temp = make_unique<Resource>("heap_resource_1");
heap_unique<Resource> heap_owner_1 = temp;
Так должно быть нельзя (юник один). Наверно используется какой-то хитрый конструктор &&. Ну ладно. Следующая строка (weak) вопросов не вызывает. Но вот потом.. какой рез-т ожидается от move? Что перемещаем, данные или только "оболочку"? Вроде данные, и ...weak автоматом ссылается на новый адрес(?). Не знаю насколько верны мои предположения, но во всяком случае

- плохо уже то что это не интуитивно и вызывает (ненужные) вопросы

- клиент (пользующий weak) может рассчитывать на неизменность адреса и рухнуть при его смене

- да, и интересно узнать какие резоны (или необходимость) в разделении на heap_unique и
inplace_unique? Пока не уловил в чем их половая разница

Включать "стандартную лексику" (типа "читай доку" и.т.п.) не стоит, она справедлива уже после того как решение использовать либу принято. А до того "симпатично или как"  Улыбающийся

От move ожидается такой же результат, как от move умных указателей из std, кто с ними знаком, использование токенов не должно вызывать затруднений. Перемещается, грубо говоря, связь с объектом, владение объектом.

Про разницу inplace_unique и heap_unique  ssoft расписывал. Вариант 1 - inplace, все остальные - heap.
Записан

Пока сам не сделаешь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #92 : Февраль 12, 2020, 11:22 »

Да, но от вумных (вернее от их беспросветной тупости) я страдаю гораздо больше Улыбающийся
А вы уверены, что причина в беспросветной тупости именно умных указателей? Улыбающийся
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #93 : Февраль 12, 2020, 11:58 »

От move ожидается такой же результат, как от move умных указателей из std, кто с ними знаком, использование токенов не должно вызывать затруднений. Перемещается, грубо говоря, связь с объектом, владение объектом.
Ну значит у Вас все верно (по крайней мере формально)
Про разницу inplace_unique и heap_unique  ssoft расписывал. Вариант 1 - inplace, все остальные - heap.
Понял, типа "хранит сам". По-моему избыточно, но Вам виднее

C++ Object Token Library предоставляет примитивы, которые контроль корректности использования ассоциативных связей, перекладывают на компилятор. Некий синтаксический сахар, чтобы случайно не выстрелить себе в ногу).

Для тех, кто не готов отдать контроль корректности использования ассоциативных связей компилятору, эта библиотека не нужна.
Я бы не стал трогать такие обшие вещи как "ассоциативные связи", и не стал бы пытаться как-то замазать (вумные) "указатели", наоборот, это лучше подчеркнуть. Почему - вот пример

Пусть абстрактная задача Car/Engine/Monitor стала реальной (это легко представить, пример вполне удачен), и обзавелась небольшим UI - списком Engine. И пользователь говорит напр:
Цитировать
Спасибо, мне нравится. Но вот в списке engine мне нужно чтобы engin'ы за которыми установлены монитор(ы) показывались с оранжевыми иконками, остальные - с желтыми
Или чуть по-другому
Цитировать
При правом нажатии на айтем engine выпадает контекстное меню из которого я могу открыть один из наблюдающих мониторов, и также удалить/назначить монитор
Конечно это "смешные" задачки, и цена им 2 копейки, но... никакие вумные указатели здесь не помогут. Да, имея Monitor можно знать что он ссылается на Engine, но не наоборот, и придется заводить контейнер "ссылающихся", руками устанавливать/разрывать связи и.т.д. Тогда что толку от вумного указателя (что сидит в Monitor) если тот же ф-ционал дублирован вручную?

Думается что сама концепция (не побоюсь этого слова) вумных указателей ограничена, это как бы "билет в один конец", думки были об удобном операторе ->. И поскольку либа (или ее автор) это оставляет "как есть" - лучше про "ассоциации" не распространяться.
  
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #94 : Февраль 12, 2020, 12:46 »

Я бы не стал трогать такие обшие вещи как "ассоциативные связи", и не стал бы пытаться как-то замазать (вумные) "указатели", наоборот, это лучше подчеркнуть.
...

Код можно воспринимать по разному: для одних это структуры данных и указатели между ними, для других это ресурсы и потребители, для третьих - объекты и ассоциативные связи между ними, для других ещё что-то. Причём код может быть один и тот же Улыбающийся. Вы, судя по всему, из первых, а я, в большинстве случаев, из третьих. Поэтому со своей колокольни и рассуждаю. Пассажи про UML в документации библиотеки можно и пропустить, если взгляд с этой стороны кого-то не интересует. Можно токены воспринимать как умные указатели с определёнными характеристиками.

Кстати, хотел сказать спасибо за то, что потратили время и предоставили свой вариант решения задачи Car. Серьёзно. Напомнили мне про старые времена, а то я уже стал забывать, как оно было, с голыми указателями Улыбающийся.
Записан

Пока сам не сделаешь...
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #95 : Февраль 12, 2020, 14:07 »

А вообще нужна обёртка-токен над объектом-по-месту? Есть варианты использования, когда без неё тяжко?

Она нужна только для обеспечения однообразия интерфейса доступа к значению, чтобы вариант heap_* легко можно было заменить на inplace_* при необходимости.

По сути после операции move над значением, для ассоциации weak реализуется UB. То что weak без контроля доступа вообще на что-то ссылается - это скорее баг, чем фитча.
Вообще, такой же фокус можно и с heap_unique провернуть: std::move(*heap_owner_1) и тоже фигня получится. Ладно, это тема отдельного разговора.

Поразмышляем ... )
Ассоциативная связь агрегации с экземпляром значения является первичной. Она может быть свойством (является членом другого значения), параметром или переменной (формируется в экземпляре активности). Все остальные ассоциативные связи формируются на основании этой.

Перемещение значения из одного экземпляра уничтожает ассоциативную связь агрегации (за счет перевода экземпляра значения в неопределенное состояние, что в принципе сродни его уничтожению). Так как ассоциативная связь агрегации с таким экземпляром значения разрушается, то и все другие ассоциативные связи с ним также становятся невалидными. Использование любой связи с таким экземпляром значения является UB. Повторная инициализация экземпляра значения требует формирования всех ассоциативных связей заново.

То, что в одном случае получается такое поведение, а в другом другое - это и есть UB. С таким же успехом можно с большой вероятностью получить сохранение валидности ссылок на пересозданный экземпляр в куче (распределение нового значения легко может оказаться в том же месте, где до этого освободилась память из под старого).
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #96 : Февраль 12, 2020, 15:38 »

А вообще нужна обёртка-токен над объектом-по-месту? Есть варианты использования, когда без неё тяжко?

Она нужна только для обеспечения однообразия интерфейса доступа к значению, чтобы вариант heap_* легко можно было заменить на inplace_* при необходимости.

Я тоже думал, что такая штука нужна для унификации передачи и доступа к объекту. Она должна быть перемещаемой, но связи с ней можно формировать только после того, как она "доехала до места" и после этого не двигать. Т.е. нужно следить не только за тем, чтоб объект не удалился, но и не переместился, чтобы raw::weak не стали висячими. Достаточно жёсткие требования, они меня и останавливали от inplace токена Улыбающийся. Но если потребность в таком есть, подумаю, чтобы добавить.

Перемещение значения из одного экземпляра уничтожает ассоциативную связь агрегации (за счет перевода экземпляра значения в неопределенное состояние, что в принципе сродни его уничтожению). Так как ассоциативная связь агрегации с таким экземпляром значения разрушается, то и все другие ассоциативные связи с ним также становятся невалидными. Использование любой связи с таким экземпляром значения является UB. Повторная инициализация экземпляра значения требует формирования всех ассоциативных связей заново.

Логично. В связи с этим, я ещё больше не понимаю упорство разработчиков gsl::not_null не допускать состояния moved-from, если можно переместить сам объект и всё равно сломать этот not_null. Они недавно даже запретили конструктор перемещения, теперь он копируется на каждый чих, даже когда std::move(not_null) пишешь Улыбающийся. Там ещё Herb Sutter вещает про "relocation/destructive-move leaves an object that is guaranteed to be no longer used" or similar (in those proposals, including even its dtor won't be called)", хотя конкретно std::unique_ptr<T> нормально зануляется и тогда в его деструкторе ничего страшного не случается. Или они знают что-то такое, о чём я не подозреваю? Улыбающийся
Записан

Пока сам не сделаешь...
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #97 : Февраль 12, 2020, 17:03 »

Логично. В связи с этим, я ещё больше не понимаю упорство разработчиков gsl::not_null не допускать состояния moved-from, если можно переместить сам объект и всё равно сломать этот not_null. Они недавно даже запретили конструктор перемещения, теперь он копируется на каждый чих, даже когда std::move(not_null) пишешь Улыбающийся. Там ещё Herb Sutter вещает про "relocation/destructive-move leaves an object that is guaranteed to be no longer used" or similar (in those proposals, including even its dtor won't be called)", хотя конкретно std::unique_ptr<T> нормально зануляется и тогда в его деструкторе ничего страшного не случается. Или они знают что-то такое, о чём я не подозреваю? Улыбающийся

Не у всех объектов возможен валидный "null" state. У юника и вектора - возможен, с ними проблем нет.
C gsl::not_null проблема следующая:
Код:
gsl::not_null<std::unique_ptr<int>> i(new int(10));

auto j = std::move(i);
assert(i.get()); // ooops контракт нарушен, ведь i значится как NOT null, а там ноль. Как так??
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #98 : Февраль 12, 2020, 17:47 »

C gsl::not_null проблема следующая:
Код:
gsl::not_null<std::unique_ptr<int>> i(new int(10));

auto j = std::move(i);
assert(i.get()); // ooops контракт нарушен, ведь i значится как NOT null, а там ноль. Как так??

С чего бы вдруг? После move нет требования гарантровать работоспособность экземпляра значения. Вызов любых методов или обращение к членам является UB. i должен быть способен корректно удалиться и всё.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #99 : Февраль 12, 2020, 17:54 »

Не у всех объектов возможен валидный "null" state.

Правильно. Вопрос, можно ли такие объекты вообще перемещать, и что можно с такими moved-from объектами делать? То, что к ним лучше не обращаться - это понятно. Их надо либо не трогать, чтоб они удалились или присвоить им новое значение, если это возможно. Т.е. в общем-то, к moved-from объекту можно относиться как-будто его удалили, и последующие возможные обращения к нему считать невалидными и отслеживать статическими анализаторами. Простые случаи уже отлавливаются, например, Clang-Tidy bugprone-use-after-move, в CppCheck тоже подобная диагностика есть.

C gsl::not_null проблема следующая:
Код:
gsl::not_null<std::unique_ptr<int>> i(new int(10));

auto j = std::move(i);
assert(i.get()); // ooops контракт нарушен, ведь i значится как NOT null, а там ноль. Как так??

В строке assert(i.get()); статический анализатор (а лучше сам компилятор), должен выдавать предупреждение о доступе к moved-from объекту.

Вот на такой код:
Код
C++ (Qt)
#include <otn/all.hpp>
#include <iostream>
 
int main()
{
   otn::unique<int> i(new int(10));
 
   auto j = std::move(i);
   std::cout << *i << std::endl;
}
у меня прямо сейчас выводятся предупреждение для строки std::cout << *i << std::endl; от CppCheck и Clang-Tidy.

Т.е. в этом отношении, всё что требуется от not_null после перемещения - это спокойно умереть и не выкинуть какой-нибудь фокус в деструкторе.

По-моему, от запрета перемещения они больше проблем поимеют, чем "защитят" его.
« Последнее редактирование: Февраль 12, 2020, 17:58 от ViTech » Записан

Пока сам не сделаешь...
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #100 : Февраль 12, 2020, 18:14 »

После move нет требования гарантровать работоспособность экземпляра значения. Вызов любых методов или обращение к членам является UB. i должен быть способен корректно удалиться и всё.

Да, но некоторые типы объектов после перемещения находятся в валидном определённом состоянии. Например, те же умные указатели std, которые, по классификации CppOtl являются optional.

Код
C++ (Qt)
#include <memory>
#include <iostream>
 
int main()
{
   auto i = std::make_shared<int>(10);
   auto j = std::move(i);
   auto k = i;
   std::cout << *j << std::endl;
}

Анализаторы возбуждаются на auto k = i;, хотя код валидный. Нужно как-то эти случаи различать и научить анализаторы их корректно обрабатывать.
Записан

Пока сам не сделаешь...
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #101 : Февраль 12, 2020, 19:32 »

Да, но некоторые типы объектов после перемещения находятся в валидном определённом состоянии. Например, те же умные указатели std, которые, по классификации CppOtl являются optional.
Анализаторы возбуждаются на auto k = i;, хотя код валидный. Нужно как-то эти случаи различать и научить анализаторы их корректно обрабатывать.

То что что-то остается в валидном состоянии - это всего лишь удобство реализации, просто полное уничтожение экземпляра может быть нерациональным с точки зрения производительности, для таких экземпляров вводят термин "частично сформированный". В общем случае move - это способ показать явно, что более данный экземпляр значения использован не будет (указание намерения уничтожения до окончания области видимости). Валидность экземпляра значения после move не гарантируется. Это, конечно, не является обязательным требованием, однако в общем случае лучше делать так, чтобы не иметь логических разночтений.

Если реально необходимо произвести обмен значениями, то нужно использовать swap.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #102 : Февраль 13, 2020, 08:39 »

Перемещение значения из одного экземпляра уничтожает ассоциативную связь агрегации (за счет перевода экземпляра значения в неопределенное состояние, что в принципе сродни его уничтожению). Так как ассоциативная связь агрегации с таким экземпляром значения разрушается, то и все другие ассоциативные связи с ним также становятся невалидными. Использование любой связи с таким экземпляром значения является UB. Повторная инициализация экземпляра значения требует формирования всех ассоциативных связей заново.
На том же примере
Код
C++ (Qt)
   heap_unique<Resource> heap_owner_1 = make_unique<Resource>("heap_resource_1");
   weak<Resource>        heap_weak{heap_owner_1.get()};
   ...
   heap_unique<Resource> heap_owner_2 = std::move(heap_owner_1);
Верно ли я понял что heap_weak.get() должен возвращать null после move ?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #103 : Февраль 13, 2020, 08:44 »

Напомнили мне про старые времена, а то я уже стал забывать, как оно было, с голыми указателями Улыбающийся.
К сожалению, далеко не весь ф-ционал реализованный "в лоб" достижим с Вашей либой. Конечно это нормально (есть область применения и.т.п.), но все-таки хотелось бы.
Код:
Рано еще утюжок бросать
Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #104 : Февраль 13, 2020, 09:44 »

То что что-то остается в валидном состоянии - это всего лишь удобство реализации, просто полное уничтожение экземпляра может быть нерациональным с точки зрения производительности, для таких экземпляров вводят термин "частично сформированный". В общем случае move - это способ показать явно, что более данный экземпляр значения использован не будет (указание намерения уничтожения до окончания области видимости). Валидность экземпляра значения после move не гарантируется. Это, конечно, не является обязательным требованием, однако в общем случае лучше делать так, чтобы не иметь логических разночтений.

Валидность экземпляра значения после move зависит от операции, обычно это move constructor и move assignment operator, и в них определяется (указывается в документации, если она есть Улыбающийся), в каком состоянии останется объект-источник. Обычно там выполняется swap с объектом, созданным конструктором по умолчанию, если он есть. Так что swap "снаружи", или какие-то другие действия по инициализации в "пустое" состояние, могут быть избыточными и неудобными в использовании. По-моему, эта ситуация похожа на noexcept, можно, например атрибутами для Lifetime Profile, как-то помечать, в каком состоянии окажется объект после перемещения, чтобы предоставить  статическим анализаторам больше информации.

Если реально необходимо произвести обмен значениями, то нужно использовать swap.

Вот со swap у gsl::not_null проблемы и начнутся Улыбающийся Когда они сделают = delete для move construction и move assignment, то отвалится std::swap, и придётся лепить костылик. Мелочь, но всё же. Потом возникнет вопрос, что можно с таким неперемещаемым gsl::not_null<unique> вообще делать? Не удивлюсь, что чуть меньше, чем ничего Улыбающийся.
Записан

Пока сам не сделаешь...
Страниц: 1 ... 5 6 [7] 8 9   Вверх
  Печать  
 
Перейти в:  


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