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

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

Страниц: [1] 2 3 ... 5   Вниз
  Печать  
Автор Тема: Ненулевые указатели  (Прочитано 33949 раз)
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« : Ноябрь 11, 2019, 19:14 »

Начало:
А вы пользуетесь этим gsl::not_null? Какие ощущения? И как у него с поддержкой умных указателей (в частности unique_ptr)?

К сожалению, не пользуюсь=( Только недавно перешли на с++17 моими стараниями (был с++11), а gsl хочет с++14 минимум. В ближайших планах есть.
gsl:span юзал, вот это вещь, да.
С умными указателями вроде всё неплохо, почему нет?

Первое, что я попробовал с gsl::not_null, было следующее:
Код
C++ (Qt)
#include <memory>
#include <gsl/pointers>
 
using namespace std;
 
int main()
{
   gsl::not_null<unique_ptr<int>> unique_p{make_unique<int>(42)};
   gsl::not_null<shared_ptr<int>> shared_p{make_shared<int>(42)};
 
   return 0;
}

Строка с unique_ptr компилируется с ошибкой:
Код:
/opt/Library/GSL/include/gsl/pointers:81: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
   81 |     constexpr not_null(T u) : ptr_(u)
      |                                     ^
Т.е. осуществляется попытка скопировать unique_ptr, а не переместить.

В связи с этим у меня возник вопрос: когда я пишу gsl::not_null<unique_ptr<int>>, то хочу сделать что-то странное? Или я что-то делаю не так?
Записан

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

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Ноябрь 11, 2019, 20:04 »

И правда, с юником оно не работает.

Я, кстати, еще наброшу - юник_птр вообще говно, его нельзя сделать объявить константным.
Юзкейз - мочь форвардить его в функции но запретить явно вызывать .release().
"константный" юник_птр бы решил все проблемы=)
« Последнее редактирование: Ноябрь 11, 2019, 20:09 от Авварон » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #2 : Ноябрь 11, 2019, 20:52 »

И правда, с юником оно не работает.

Там вообще много интересного, связанного с умными указателями.
Например:
not_null<shared_ptr> overhead
Цитировать
What is the intended usage of not_null with std::shared_ptr? There is a significant overhead to wrapping std::shared_ptr in not_null because every access results in a costly copy of the shared_ptr. As not_null cannot be used with unique_ptr, it seems that not_null is not really usable with smart pointers in general.

Вот пулл реквест, чтобы можно было перемещать unique_ptr: not_null no longer requires a copyable pointer type.
Но, видать, это мало кому нужно Улыбающийся.
Записан

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

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Ноябрь 11, 2019, 21:15 »


Там вообще много интересного, связанного с умными указателями.
Например:
not_null<shared_ptr> overhead


Ну это тоже следствие того что ctor принимает копию указателя а get() возвращает копию.

Но да, с вумными указателями это особо не нужно.
Кроме того, там лезут проблемы, например:
Код:
not_null<unique_ptr<int>> p(make_unique(42));
p.get().release(); // oops контракт нарушен

Конечно, повторный вызов get() выявит нарушение контракта, но хотелось бы запретить такой вызов "на корню", т.е. get() вообще в идеале не должен ничего проверять (контракт был нарушен где-то ДО get() и вот там это и надо проверять - в кторе ли или в операторе=)
Возможно, это можно сделать через частичную специализацию для разных типов - одна для тривиальных T*, вторая для вумных (т.е. get() возвращает всегда T* просто в случаев вумных делает еще один .get()). Короче всё оказалось не так тривиально как я думал=(
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #4 : Ноябрь 11, 2019, 21:18 »

Я, кстати, еще наброшу - юник_птр вообще говно, его нельзя сделать объявить константным.
Юзкейз - мочь форвардить его в функции но запретить явно вызывать .release().
"константный" юник_птр бы решил все проблемы=)
Не очень понятен юзкейс. Можете пример привести.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #5 : Ноябрь 11, 2019, 22:07 »

Я, кстати, еще наброшу - юник_птр вообще говно, его нельзя сделать объявить константным.
Юзкейз - мочь форвардить его в функции но запретить явно вызывать .release().
"константный" юник_птр бы решил все проблемы=)
Не очень понятен юзкейс. Можете пример привести.


Код:
unique_ptr<int> p = foo();
p.release(); // ok
bar(move(p)); // ok

Код:
const unique_ptr<int> p = foo();
p.release(); // !ok, не скомпилится, хорошо
bar(move(p)); // тоже !ok, а вот это было бы неплохо скомпилить

То есть по-хорошему нужен какой-то immutable_unique_ptr который нельзя занулить, но можно мувнуть. Такого нет и сделать стандартными средствами нельзя => возникает нужда в not_null.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #6 : Ноябрь 11, 2019, 22:14 »

То есть по-хорошему нужен какой-то immutable_unique_ptr который нельзя занулить, но можно мувнуть.
Мувая указател в функцию, вы передаете все права на ресурс этой функции. При выходе из нее он удалится. Так какая разница, что там делает функция с этим ресурсом? Хочет релизить - пусть релизит.

Не хотите передавать права - отдавайте функции указатель по константной ссылке, она не сможет занулить.
« Последнее редактирование: Ноябрь 12, 2019, 08:56 от Old » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #7 : Ноябрь 12, 2019, 09:55 »

Код:
const unique_ptr<int> p = foo();
p.release(); // !ok, не скомпилится, хорошо
bar(move(p)); // тоже !ok, а вот это было бы неплохо скомпилить
То есть по-хорошему нужен какой-то immutable_unique_ptr который нельзя занулить, но можно мувнуть.

Тут попытка изменить константный объект, естественно он сопротивляется. Это ко всем типам относится, не только unique_ptr такой плохой. Если нужно обеспечить, чтобы в указателе всегда был какой-то объект, то это не обязательно связано с иммутабельностью. У него поведение может отличаться (нет release(), reset(nullptr) и прочее). При этом можно заменить управляемый объект на другой, сделать swap с другим указателем и т.д. Т.е. нужен именно какой-то not_null_unique_ptr.

Такого нет и сделать стандартными средствами нельзя => возникает нужда в not_null.
Если такого стандартного нет, значит нужно сделать нестандартный Улыбающийся.
Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Ноябрь 12, 2019, 10:02 »

Т.е. нужен именно какой-то not_null_unique_ptr.
Для чего он нужен? Я не могу придумать юзкейс для него. Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #9 : Ноябрь 12, 2019, 10:49 »

Для чего он нужен? Я не могу придумать юзкейс для него. Улыбающийся

Например, когда какой-то объект (составной/composite) уникально владеет точно одним другим объектом (частью/part) и нужно соблюдать целостность этой связи. Чтобы явно сказать, что в этом указателе точно есть объект, и не нужно этот указатель проверять на null, а можно сразу к нему обращаться. В отличие от optional_unique_ptr(std::unique_ptr), где объект может быть, а может и не быть, и тогда перед обращением к указателю его обязательно нужно проверить. Если обратиться к UML, то not_null_unique_ptr может реализовать конец ассоциативной связи с композитной агрегацией и кратностью [1..1], в то время как .  optional_unique_ptr тоже может реализовать композитную агрегацию, но уже с кратностью [0..1]. Как в этом примере.
Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #10 : Ноябрь 12, 2019, 11:14 »

Например, когда какой-то объект (составной/composite) уникально владеет точно одним другим объектом (частью/part) и нужно соблюдать целостность этой связи. Чтобы явно сказать, что в этом указателе точно есть объект, и не нужно этот указатель проверять на null, а можно сразу к нему обращаться. В отличие от optional_unique_ptr(std::unique_ptr), где объект может быть, а может и не быть, и тогда перед обращением к указателю его обязательно нужно проверить. Если обратиться к UML, то not_null_unique_ptr может реализовать конец ассоциативной связи с композитной агрегацией и кратностью [1..1], в то время как .  optional_unique_ptr тоже может реализовать композитную агрегацию, но уже с кратностью [0..1]. Как в этом примере.
Не, я про перемещение указателя в функцию. Про то, о чем писал Аварон. Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #11 : Ноябрь 12, 2019, 11:41 »

Не, я про перемещение указателя в функцию. Про то, о чем писал Аварон. Улыбающийся

А, ну судя по "нельзя занулить, но можно мувнуть", то, возможно, нужно выразить в типе параметра функции, что в этом указателе точно есть объект, можно не проверять на null, нельзя удалять объект из этого указателя (но можно ли заменить на другой?), как-то поработать с этим объектом, передать владеющий указатель дальше (в другую функцию, в поле класса, возможно в очередь команд/событий) и в текущей функции забыть про него. Т.е. функция может и не быть конечной остановкой. Такая у меня версия, но могут быть и другие Улыбающийся.
Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Ноябрь 12, 2019, 14:02 »

Т.е. функция может и не быть конечной остановкой.
Функции отдали во владение объект, сказали делай с ним что хочешь. Выше по стеку этот объект никому не нужен.
Только функции решать, что сделать с этим объектом. Если нужно отдать дальше, то она не будет его удалять.

Кого мы пытаемся ограничить этим функционалом, писателя функции? Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #13 : Ноябрь 12, 2019, 14:05 »

Кого мы пытаемся ограничить этим функционалом, писателя функции? Улыбающийся

Кого мы пытаемся ограничить, запрещая писать gsl::not_null<int *> p = nullptr? Писателя функции?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Ноябрь 12, 2019, 14:12 »

Кого мы пытаемся ограничить, запрещая писать gsl::not_null<int *> p = nullptr? Писателя функции?
Мы говорим о разном функционале.
Перемещение unique_ptr в функцию != запрету передачи nullptr.
Вы хотели запретив вызов release юника в функции добиться невозможности передачи nullptr в вызове вложенной функции?
Записан
Страниц: [1] 2 3 ... 5   Вверх
  Печать  
 
Перейти в:  


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