powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / shared_ptr как возвращаемый результат
25 сообщений из 45, страница 1 из 2
shared_ptr как возвращаемый результат
    #39472848
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
сомнения меня гложут, как правильно делать?

раньше, если я возвращал какую-то переменную класса геттером, я делал так:
Код: plaintext
1.
const T& A::Get() {...}


теперь, если у меня в классе переменная идёт, как shared_ptr<T>, то я и должен возвращать ровно shared_ptr<T>, чтобы создалась ещё одна копия, и счётчик таким образом увеличился на 1.
Код: plaintext
1.
shared_ptr<T> A::Get() {...}


если же я сделаю так:
Код: plaintext
1.
shared_ptr<T>& A::Get() {...}


то это выстрел в ногу, так как счётчик не изменится.

вроде так. Если я выше не прав, то поправьте.
если прав, то дальше меня тревожит то, что я в геттере возвращаю копию. Т.е. создаётся ещё один объект, зовётся конструктор и всё такое.

Как сложить эти две вещи вместе, возвращать ссылку на объект(это быстро) и авто-контролировать счётчик (это безопасно)? Как вообще правильно работать в данном случае с shared_ptr<T> снаружи классов?
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472865
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMb, ты просто забыл включить мозг. ;)
Если ты объявил переменную типа shared_ptr<T> на стеке внутри метода, то после выхода из метода счетчик останется неизменным, так как предыдущий экземпляр shared_ptr<T> будет уничтожен деструктором и счетчик уменьшен на ту же единицу.
Если ты объявил "shared_ptr<T>" на стеке, то вернуть его как "shared_ptr<T>&" ты не можешь, так как, опять же, его экземпляр будет разрушен после выхода из области видимости. Возвращать его как "shared_ptr<T>&" ты можешь, например, если объявил этот указатель как "static shared_ptr<T>&".
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472882
Фотография PPA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devCEMb, ты просто забыл включить мозг. ;).
он пишет про член - где вы увидели возврат ссылки на локальную переменную?

2CEMb - геттер у тебя ведь простой без логики?
зачем он у тебя лежит в cpp? помести его в h и он заинлайнится оптимизатором.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472913
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PPAон пишет про член - где вы увидели возврат ссылки на локальную переменную?Здесь подразумевается возврат экземпляра класса-указателя на член типа "T" экземпляра класса "A", а не то, что "shared_ptr<T>" объявлен как член класса. Здесь "T", это тип члена класса "A", а "shared_ptr<T>", это подобие "T*" или "T&", но если два последних, это простые типы указателя и ссылки на "T", то "shared_ptr<T>", это класс указателя (некая реализация сборки мусора).
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472919
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472925
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CEMb,

передача по значению - есть передача по значению. И в случае с shared_ptr она может быть достаточно тяжёлой.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472941
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YesSqlпередача по значению - есть передача по значению. И в случае с shared_ptr она может быть
достаточно тяжёлой.

Во-первых, современные компиляторы делают copy elimination, что сильно облегчает процесс.
Во-вторых, современная парадигма С++ игнорирует вопросы быстродействия в пользу легко
читаемого кода.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472945
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devCEMb, ты просто забыл включить мозг. ;)я не могу включить то, чего нет, поэтому и пришёл с вопросом.
PPAзачем он у тебя лежит в cpp?а как по коду ты понял, где он лежит?

rdb_devЗдесь подразумевается возврат экземпляра класса-указателя на член типа "T" экземпляра класса "A", а не то, что "shared_ptr<T>" объявлен как член класса.ненене, именно объявлен как shared_ptr<T>, но если это пагубная практика, то расскажите, как правильно. Имхо, неправильно отдавать кому-то shared_ptr<T> если сам объект shared_ptr<T> не является. Грубо говоря, управление памятью должно быть единообразно. Иначе, как вариант: если после геттера объект класса А будет уничтожен, код, получивший shared_ptr<T> не узнает об этом и помешать этому не сможет.

Заново.
Код: plaintext
1.
2.
3.
4.
class A {
shared_ptr<T> t_;
shared_ptr<T> Get() {return t_;}
};

Get() создаёт копию объекта shared_ptr<T>, который инициализируется указателем на t_, т.е. с копирование адреса t_ у нас тут проблем нет, но вот с вызовом конструктора shared_ptr<T> - как бы накладные расходы, да? Учение говорит, что возвращать надо ссылки(или указатели, когда нельзя ссылки), иначе будет неявно зваться конструктор.
Но (тот самый вопрос), если мы сделаем так:
Код: plaintext
1.
shared_ptr<T>& Get() {return t_;}

то получим ссылку на t_, копирование указателя пройдёт быстро, никаких лишних вызовов и кода (как велит учение), но, опять же, если объект класса А будет уничтожен после геттера, геттер узнает об этом(хоть с трудом, но можно), но помешать этому не сможет.

Вопрос в том: как теперь, в связи с shared_ptr надо отдавать переменные класса. Ну или в обратную сторону: как описывать входящие параметры типа shared_ptr<T> в функциях. Если как ссылки - быстро и ненадёжно, если как объекты, то надёжно и небыстро.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472954
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YesSqlпередача по значению - есть передача по значению. И в случае с shared_ptr она может быть достаточно тяжёлой.Эээ тяжёлой, но не достаточно тяжёлой. Это просто вызов конструктора shared_ptr<T> и передача ему указателя на объект. Т.е. тяжело, но не сильно. Но передача по ссылке - всё равно легче.
Dimitry SibiryakovВо-первых, современные компиляторы делают copy elimination, что сильно облегчает процесс.А, блин, точно, там оптимизация по возвращаемому значению же... я забыл про это :(
Ну, т.е. мой вариант
Код: plaintext
1.
shared_ptr<T> Get()

- абсолютно верный? :)
Dimitry SibiryakovВо-вторых, современная парадигма С++ игнорирует вопросы быстродействия в пользу легко
читаемого кода.но при этом авторы сделали очень много, чтобы увеличить это самое быстродействие. Ладно, не будем вдаваться в детали, а то сщас начнётся...
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472966
Фотография OoCc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbYesSqlпередача по значению - есть передача по значению. И в случае с shared_ptr она может быть достаточно тяжёлой.Эээ тяжёлой, но не достаточно тяжёлой. Это просто вызов конструктора shared_ptr<T> и передача ему указателя на объект. Т.е. тяжело, но не сильно. Но передача по ссылке - всё равно легче.
Все зависит от задачи. Это не "просто вызов конструктора" это атомик или мютекс в зависимости от имплементации.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39472981
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OoCcВсе зависит от задачи. Это не "просто вызов конструктора" это атомик или мютекс в зависимости от имплементации.Ну ок. Так как тогда правильно возвращать значения и передавать параметры в функции? Или зависит от типа?
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473003
Фотография OoCc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbOoCcВсе зависит от задачи. Это не "просто вызов конструктора" это атомик или мютекс в зависимости от имплементации.Ну ок. Так как тогда правильно возвращать значения и передавать параметры в функции? Или зависит от типа?
Прелесть С++ в том что все зависит от задачи и ее дизайна. С++ может быть Java-ой а может быть и C с-классами.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473018
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbИмхо, неправильно отдавать кому-то shared_ptr<T> если сам объект shared_ptr<T> не является. Грубо говоря, управление памятью должно быть единообразно. Иначе, как вариант: если после геттера объект класса А будет уничтожен, код, получивший shared_ptr<T> не узнает об этом и помешать этому не сможет.Если ты самостоятельно разрушаешь объект, то shared_ptr об этом, по-любому, никак не узнает. Если ты используешь shared_ptr<T>, ни о каком самостоятельном разрушении экземпляра "T", на который ссылается экземпляр "shared_ptr<T>" не может быть и речи. При использовании "умных указателей", без накладных расходов не обойтись, но можно сократить количество созданий и разрушений shared_ptr при передаче его в качестве результата. Возвращай из геттера как "shared_ptr<T>&" - по ссылке и не парься! Так как в коде ты всё равно будешь делать что-то типа:
Код: plaintext
1.
shared_t<T> t = instanceA->Get();
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473040
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ошибся в написании:
Код: plaintext
1.
shared_ptr<T> t = instanceA->Get();
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473045
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OoCcПрелесть С++ в том что все зависит от задачи и ее дизайна.так мне-то в вышеприведённом коде, без atomic и mustex, как лучше делать?
rdb_devВозвращай из геттера как "shared_ptr<T>&" - по ссылке и не парься!Нет, так неправильно. Пример:
Код: plaintext
1.
2.
3.
auto t = a->Get();
delete a;
t.get(); // UB!
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473059
Фотография OoCc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbOoCcПрелесть С++ в том что все зависит от задачи и ее дизайна.так мне-то в вышеприведённом коде, без atomic и mustex, как лучше делать?
rdb_devВозвращай из геттера как "shared_ptr<T>&" - по ссылке и не парься!Нет, так неправильно. Пример:
Код: plaintext
1.
2.
3.
auto t = a->Get();
delete a;
t.get(); // UB!


С таким дизайном тебе больше подходит Java-подобная парадигма С++ 20569314
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473092
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbrdb_devВозвращай из геттера как "shared_ptr<T>&" - по ссылке и не парься!Нет, так неправильно. Пример:
Код: plaintext
1.
2.
3.
auto t = a->Get();
delete a;
t.get(); // UB!

Что именно неправильно? Если экземпляр "T" не является инкапсулированным в "A", то удаление экземпляра "A" приведет к удалению "умной ссылки", а не самого экземпляра "T", при условии, что где-либо существует еще одна валидная ссылка "shared_ptr<T>" на данный экземпляр "T". Пример:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
class A
{
private:
  shared_ptr<T> t_;

public:

  shared_ptr<T>& A::Get()
  {
    if (NULL == this->t_.get()) this->t_.reset(new T());
    return this->t_;
  }
};

A* a = new A();
shared_ptr<T> t = a->Get();
delete a;
t->someMethod(); // SUCCESS!
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473098
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чтоб было понятнее, перепишем пример так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
class A
{
private:
  shared_ptr<T> t_;

public:

  shared_ptr<T>& A::Get()
  {
    if (NULL == this->t_.get()) this->t_.reset(new T());
    return this->t_;
  }
};

A* a = new A();
shared_ptr<T>* ppT = new shared_ptr<T>(a->Get());
delete a;
(*ppT)->someMethod();  // SUCCESS!
delete ppT;
(*ppT)->someMethod();  // FAIL!
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473103
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
точнее так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
A* a = new A();
shared_ptr<T>* ppT = new shared_ptr<T>(a->Get());
delete a;
(*ppT)->someMethod();  // SUCCESS!
T* t = (*ppT).get();
delete ppT;
t->someMethod();  // FAIL!
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473174
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно возвращать ссылку на смартуказатель.
А если вызывающему коду надо продлить время жизни объекта по этой ссылке, то там надо положить эту ссылку в копию смартуказателя.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473857
Вася Уткин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Если тебе не нужно делать очень часто так:
Код: plaintext
1.
2.
a->Get()->some();                 // так
shared_ptr<T> &ptr = a->Get();    // или так (что в большинстве случаев плохая практика)

тогда возвращай по значению shared_ptr<T> A::Get() {...}

Возвращение shared_ptr по ссылке несет больше потенциальных проблем, чем по значению. Но в некоторых случаях может быть быстрее.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473894
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_dev
Код: plaintext
1.
shared_ptr<T> t = a->Get();

интересный момент. Я имел ввиду:
Код: plaintext
1.
shared_ptr<T>& t = a->Get();

И тогда delete a; уничтожит и t_ тоже (по идее должно, не проверял)
Или, иными словами:Anatoly MoskovskyА если вызывающему коду надо продлить время жизни объекта по этой ссылке, то там надо положить эту ссылку в копию смартуказателя.Т.е. получается, что если мы возвращаем ссылку на shared_ptr, мы оставляем на совести вызывающего следить за тем, жив a в момент вызова Get() или нет.
Ну ок, мне этот вариант больше нравится, спасибо всем :)
Пойду переписывать код...
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473932
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbТ.е. получается, что если мы возвращаем ссылку на shared_ptr, мы оставляем на совести вызывающего следить за тем, жив a в момент вызова Get() или нет.
Ну ок, мне этот вариант больше нравится, спасибо всем :)
Пойду переписывать код...Ну да! Представь, что тебе, по какой-то причине, понадобилось вызвать a->Get() вхолостую - без присваивания значения в вызывающей программе, чтобы инициализировать объект "T" заранее. При этом, если "shared_ptr<T>" будет возвращаться по значению, то объект будет создан дважды - в куче и на стеке (конструктором копии).
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39473965
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbЯ имел ввиду:
Код: plaintext
1.
shared_ptr<T>& t = a->Get();

И тогда delete a; уничтожит и t_ тоже (по идее должно, не проверял)Обязано! Так как "shared_ptr<T>" является инкапсулируемым, он будет разрушен при разрушении экземпляра "A" автоматически сгенерированным для этой цели кодом.
...
Рейтинг: 0 / 0
shared_ptr как возвращаемый результат
    #39474118
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbТ.е. получается, что если мы возвращаем ссылку на shared_ptr, мы оставляем на совести вызывающего следить за тем, жив a в момент вызова Get() или нет.
Ну ок, мне этот вариант больше нравится, спасибо всем :)
Пойду переписывать код...
Если программа многопоточная, то возврат ссылки (а не копии) создает точку, когда объект может быть уничтожен между возвратом и присвоением его в копию.
Поэтому, если объект используется в нескольких потоках, то ссылки использовать нельзя (кроме случаев когда вы другими способами гарантируете время жизни объекта).
Создание же копии смартуказателя это атомарная операция и гарантирует что другой поток не уничтожит объект.
...
Рейтинг: 0 / 0
25 сообщений из 45, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / shared_ptr как возвращаемый результат
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]