"ArtDenis" <15178@users.rsdn.ru> wrote in message news:1781646@news.rsdn.ru... > Думаю, потому, что для умного указателя привычнее писать >
> ptr.reset(new SomeClass);
>
> чем >
> ptr = boost::make_shared_ptr(new SomeClass);
>
Не та немножко ситуация: переменной ptr не существует, а существует функция, принимающая boost::shared_ptr. Точнее говоря, функций, принимающих boost::shared_ptr, различных типов множество. И каждый раз, чтоб вызвать такую функцию приходится писать что то вроде этого:
rg45 пишет: > Не та немножко ситуация: переменной ptr не существует, а существует функция, принимающая boost::shared_ptr. Точнее говоря, функций, принимающих boost::shared_ptr, различных типов множество. И каждый раз, чтоб вызвать такую функцию приходится писать что то вроде этого:
Ну... Ради такого редкого случая ф-цию make_shared_ptr можно написать
самостоятельно Не думаю, что она была бы полезна в общем случае.
> а может функций с такой сигнатурой писать нестоит?
Ну это вопрос более сложный.
Во-первых, от упрощения сигнатуры может усложниться реализация.
Во-вторых, в данном примере сигнатура может быть самой простой, например такой:
void some_func(boost::shared_ptr<BasicObj>);
тогда встает дилемма: либо писать сложную конструкцию, типа той, что я написал, либо для каждого кокретного класса держать в голове его базовый класс.
В-третьх, не всегда есть возможность эту сигнатуру изменить, она может быть интерфейсом "чужой" библиотеки.
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
"ArtDenis" <15178@users.rsdn.ru> wrote in message news:1781749@news.rsdn.ru... > Ну... Ради такого редкого случая ф-цию make_shared_ptr можно написать > самостоятельно Не думаю, что она была бы полезна в общем случае.
Да так оно и есть, но тогда это выглядит так, будто я пишу расширение к бусту.
А потом, мне интересен вот какой момент: реализация этой функции, как мне кажется, была бы вполне естественной в бусте, но ее там нет, может я что то упускаю из виду?
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
R>Не та немножко ситуация: переменной ptr не существует, а существует функция, принимающая boost::shared_ptr. Точнее говоря, функций, принимающих boost::shared_ptr, различных типов множество. И каждый раз, чтоб вызвать такую функцию приходится писать что то вроде этого: R>
не совсем понятно почему вы используете указатель на уже существующий объект obj_ptr вместо создания нового с помощью оператора new?
Вообще то данный подход не совсем верен.
Во-первых до вызова some_func (boost::shared_ptr<T>(obj_ptr)) где obj_ptr типа T*
создается новый объект shared_ptr который принимает владение объектом и будет уничтожать его с помощью стандартного deleter'a. И при уничтожении этого объекта shared_ptr удалится и владеемый им объект типа T*
То есть после вышупомянутого вызова obj_ptr будет указывать на несуществующую область памяти.
Вообще в вашем случае есть такие варианты вызова:
В первом случае вам самим не нужен объект T, а во втором — он вам нужен после вызова some_func.
Но в первом случае могут возникнуть проблемы если нужно передать несколько указателей:
При этом если возникнет исключение в одном из консткруторов T1 или T2, то произойдет утечка памяти. (порядок вызова этих конструкторов не определен по стандарту)
>> а может функций с такой сигнатурой писать нестоит?
R>Ну это вопрос более сложный. R>Во-первых, от упрощения сигнатуры может усложниться реализация. R>Во-вторых, в данном примере сигнатура может быть самой простой, например такой: R>
R>тогда встает дилемма: либо писать сложную конструкцию, типа той, что я написал, либо для каждого кокретного класса держать в голове его базовый класс. R>В-третьх, не всегда есть возможность эту сигнатуру изменить, она может быть интерфейсом "чужой" библиотеки.
Да нет же, суть в том, что стоит ли вообще в сигнатуру выность boost::shared_ptr
"einstein" <23471@users.rsdn.ru> wrote in message news:1782110@news.rsdn.ru... E> не совсем понятно почему вы используете указатель на уже существующий объект obj_ptr вместо создания нового с помощью оператора new? E>...
Т.о. можно сделать такой вывод: практика, когда объект создается, после этого с ним выполняются нектороые операции, пользуясь "голым" указателем, а только потом этот указатель помещается в shared_ptr является неправильной. И чтобы не способствовать этому, упомянутой функции просто не существует.
Правильно?
Posted via RSDN NNTP Server 1.9
--
Справедливость выше закона. А человечность выше справедливости.
... > При этом если возникнет исключение в одном из консткруторов T1 или T2, > то произойдет утечка памяти. (порядок вызова этих конструкторов не > определен по стандарту)
Я вот тоже не понял.
В чём принципиальная разница между
func(make_shared_ptr(new A));
и
func(shared_ptr<A>(new A));
?
Какие могут быть ошибки? В каких случаях первый код опаснее второго?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
конечно, смысл в создании shared_pointer-а в том, что бы продлить жизнь контролируемого обьекта, а зачем его указыать в сигнатуре функции, если, по идее, тот, кто передаёт указатель в функцию всё равно держит ссылку на обьект. На мой взгляд shared_pointer стоит использовать для хранения обьектов в полях структур либо контейнерах.
Здравствуйте, Tom, Вы писали:
Tom>конечно, смысл в создании shared_pointer-а в том, что бы продлить жизнь контролируемого обьекта, а зачем его указыать в сигнатуре функции, если, по идее, тот, кто передаёт указатель в функцию всё равно держит ссылку на обьект. На мой взгляд shared_pointer стоит использовать для хранения обьектов в полях структур либо контейнерах.
Это конечно все правильно. Но как поступать в случаях передачи владения указателем функцией? Т.е.
в функции создается объект, с ним выполняются определенные действия и его нужно вернуть в вызывающую функцию. Создавать объект снаружи не предлагать, допустим функция создает одного из наследников, а возвращает базовый указатель.
В теории практика не отличается от теории, но на практике — отличается
Здравствуйте, rg45, Вы писали:
R>Т.о. можно сделать такой вывод: практика, когда объект создается, после этого с ним выполняются нектороые операции, пользуясь "голым" указателем, а только потом этот указатель помещается в shared_ptr является неправильной. И чтобы не способствовать этому, упомянутой функции просто не существует. R>Правильно?
Правильно.
В добавок приведу пример, когда не избежать ситуации с созданием shared_ptr из голого указателя.
struct A {
void foo();
};
void bar(shared_ptr<A>);
void A::foo() {
bar(shared_ptr<A>(this)); // bug!
}
int main()
{
shared_ptr<A> obj(new A());
obj->foo();
// obj destructor crashes in operator delete
}
Баг в том, что создаётся два разных shared_ptr для одного и того же голого указателя. Проблема решается применением enable_shared_from_this:
struct A : boost::enable_shared_from_this<A> {...};
void A::foo() {
bar(shared_from_this()); // shared_from_this() is inherited from enable_shared_from_this
}
shared_from_this создаёт shared_ptr, использующий тот-же счётчик ссылок что и первоначальный shared_ptr<A> obj(new A()).
Здравствуйте, Tom, Вы писали:
R>>Почему? А что принимать? Обычный указатель? R>>
Tom>конечно, смысл в создании shared_pointer-а в том, что бы продлить жизнь контролируемого обьекта, а зачем его указыать в сигнатуре функции, если, по идее, тот, кто передаёт указатель в функцию всё равно держит ссылку на обьект. На мой взгляд shared_pointer стоит использовать для хранения обьектов в полях структур либо контейнерах.
Не согласен! Если речь идёт о такой ситуации, то зачем тогда вообще передавать указатель? Тут можно передавать ссылку — со ссылкой всё понятно — с ней владение не передашь. Или boost::weak_ptr.
Чаще в такой ситуации имеется в виду передача владения. А вот это уже неправильно — захватывать объект в shared_ptr внутри функции — это надо делать вне функции, а функция должна принимать уже shared_ptr.
nau>Это конечно все правильно. Но как поступать в случаях передачи владения указателем функцией? Т.е. nau>в функции создается объект, с ним выполняются определенные действия и его нужно вернуть в вызывающую функцию. Создавать объект снаружи не предлагать, допустим функция создает одного из наследников, а возвращает базовый указатель.
Согласен, бывает так, конечно в таком случае нужно возвращать шаред ptr. Я вообще предпочитаю пользоваться интрузив птр-ом
R>По аналогии с boost::make_tuple или std::make_pair. R>Может быть есть веские причины, по которым эту функцию не стали делать?
Ещё одна проблема есть, которую вроде никто не упоминал. Одна из причин использования динамических объектов — динамический полиморфизм. Поэтому зачастую в сигнатуре функции написано shared_ptr<ISomeInterface>, а ты в функцию передаёшь SomeInterfaceImpl*. Преобразование указателя из SomeInterfaceImpl* в ISomeInterface* иногда надо контролировать. Для чего в shared_ptr есть не только:
Здравствуйте, kan_izh, Вы писали:
_>Я вот тоже не понял.
_>В чём принципиальная разница между _>func(make_shared_ptr(new A)); _>и _>func(shared_ptr<A>(new A)); _>?
_>Какие могут быть ошибки? В каких случаях первый код опаснее второго?
Во-первых, как я понимаю, вы хотите использотвать эту ф-цию, чтобы лишний раз не писать тип T и чтобы он выводился автоматически (т.к. шаблонные ф-ции позволяют это делать)
Давайте проанализируем что происходит при вызове func(make_shared_ptr(new A)) ?
Создается новый объект A в куче, передается ф-ции, она инициализирует в строке (1) временный объект типа shared_ptr<T> значением этого указателя и, таким образом принимает владение этим объектом. Счетчик ссылок при этом устанавливается равным 1. Далее при возврате из ф-ции происходит копирование этого временного объекта в другой временный объект shared_ptr<T> (который уже потом передается func, возможно опять с дополнительным копированием). При копировании с помощью конструктора копирования shared_ptr счетчик ссылок увеличивается и становится 2, далее после выхода из области видимости первого объекта он опять становится равным единице.
Я привел пример где удобство записи вполне может обернутся неоправданным уменьшением производительности (особенно в многопоточных приложениях, где обращение к счетчику ссылок возможно нуждается в исп. объектов синхронизации).
Здравствуйте, einstein, Вы писали:
E>Я привел пример где удобство записи вполне может обернутся неоправданным уменьшением производительности (особенно в многопоточных приложениях, где обращение к счетчику ссылок возможно нуждается в исп. объектов синхронизации).
Я думаю, причина была не в этом.
С умным указателем вообще медленнее работать, т.к. там всё равно используется разделяемый счётчик. Быстро работать с голым указателем и самому помнить, где его создал и где его надо удалить.
R>>По аналогии с boost::make_tuple или std::make_pair. R>>Может быть есть веские причины, по которым эту функцию не стали делать?
R>Ещё одна проблема есть, которую вроде никто не упоминал. Одна из причин использования динамических объектов — динамический полиморфизм. Поэтому зачастую в сигнатуре функции написано shared_ptr<ISomeInterface>, а ты в функцию передаёшь SomeInterfaceImpl*. Преобразование указателя из SomeInterfaceImpl* в ISomeInterface* иногда надо контролировать. Для чего в shared_ptr есть не только:
R>
einstein wrote:
> Во-первых, как я понимаю, вы хотите использотвать эту ф-цию, чтобы > лишний раз не писать тип T и чтобы он выводился автоматически (т.к. > шаблонные ф-ции позволяют это делать)
Да.
> Давайте проанализируем что происходит при вызове > func(make_shared_ptr(new A)) ? > Создается новый объект A в куче, передается ф-ции, она инициализирует в > строке (1) временный объект типа shared_ptr<T> значением этого указателя > и, таким образом принимает владение этим объектом. Счетчик ссылок при > этом устанавливается равным 1. Далее при возврате из ф-ции происходит > копирование этого временного объекта в другой временный объект > shared_ptr<T> (который уже потом передается func, возможно опять с > дополнительным копированием). При копировании с помощью конструктора > копирования shared_ptr счетчик ссылок увеличивается и становится 2, > далее после выхода из области видимости первого объекта он опять > становится равным единице.
Добавим 'inline', тогда компилятор в подавляющем большинстве случаев сгенерит точно такой же код для обоих конструкций
(имхо, не пробовал).
> Я привел пример где удобство записи вполне может обернутся неоправданным > уменьшением производительности (особенно в многопоточных приложениях, > где обращение к счетчику ссылок возможно нуждается в исп. объектов > синхронизации).
В общем, потестить надо...
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan_izh, Вы писали:
_>Добавим 'inline', тогда компилятор в подавляющем большинстве случаев сгенерит точно такой же код для обоих конструкций _>(имхо, не пробовал).
Если там синхронизация, то не соптимизирует.
Тем более, что shared_ptr шаблонный, значит и так доступен для встраивания.
remark wrote: > Имелась в виду ситуация когда надо писать: > > someFunc(IInterfacePtr(p, dynamic_cast_tag())); > C make_shared_ptr будет проблематичнее.
Добавить второй необязательный параметр в make_shared_ptr?..
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan_izh, Вы писали:
_>remark wrote: >> Имелась в виду ситуация когда надо писать: >> >> someFunc(IInterfacePtr(p, dynamic_cast_tag())); >> C make_shared_ptr будет проблематичнее.
_>Добавить второй необязательный параметр в make_shared_ptr?..