Shared_ptr и ссылки в C++
-
05-07-2019 - |
Вопрос
Ссылки в C++ — это удобная конструкция, позволяющая упростить следующий код C:
f(object *p){
//do something
}
int main(){
object* p = (object*) calloc(sizeof(object));
f(p);
}
к
f(object& o){
//do something
}
int main(){
object o = object();
f(o);
}
Общие указатели — еще одно удобство C++, упрощающее управление памятью.Однако я не уверен, как передать shared_ptr
к функции типа f(object& o)
который принимает аргументы по ссылке?
f(object& o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(*p);
}
Будет ли увеличиваться общий указатель, когда его объект передается по ссылке в функцию?
Решение
Возьмите shared_ptr
по значению, и количество ссылок увеличится. Это проще, когда вы typedef
это:
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr obj)
{
obj->/* stuff*/;
obj.reset(); //only resets this local copy, that means:
// reduce reference count (back to 1), and
// set obj to point at null.
}
int main(void)
{
object_ptr obj(new object());
foo(obj);
}
Помните, что ссылки - это псевдонимы. Когда вы передаете по ссылке, вы не передаете указатели, копии и т. Д., А накладываете псевдоним на другой объект. (На самом деле они реализованы в виде указателей):
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr& obj)
{
obj.reset(); // the references was never increased, since a copy has not
// been made, this *is* obj in main. so the reference
// goes to 0, and obj is deleted
}
int main(void)
{
object_ptr obj(new object);
foo(obj); // after this, obj has been reset!
}
Всегда помните, чтобы быть const
правильно, чтобы избежать ошибок:
typedef boost:shared_ptr<object> object_ptr;
void foo(const object_ptr& obj)
{
obj.reset(); // cannot do!
}
int main(void)
{
object_ptr obj(new object);
foo(obj);
}
Я думаю, что вы должны предпочесть передавать умные указатели в качестве ссылок, когда это возможно, чтобы избежать посторонних приращений и уменьшений (а также копий и прочего).
Другие советы
Будет ли общий указатель увеличиваться при передаче его объекта по ссылке на функцию?
Нет, так как вы получаете доступ к необработанному указателю и затем передаете его. Вы хотите сделать что-то похожее на это:
f(shared_ptr<object> o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(p);
}
f(object& o){ //do something } int main(){ shared_ptr<object> p (new object()); f(*p); }
Будет ли увеличен общий указатель когда его объект передается по ссылке к функции?
В приведенном выше коде - нет. У p счетчик ссылок всегда будет равен 1. Вы можете проверить это в отладчике. Счетчик ссылок shared_ptr подсчитывает количество экземпляров shared_ptr, которые указывают на один и тот же объект, он не отслеживает ссылки, которые вы создаете, вызывая operator * (). И в этом нет необходимости - поскольку p гарантированно доживет до конца области действия, а вызов функции находится в той же области (или глубже), p будет во время всего вызова f (). Так что все в порядке. Р>
... если только в f вы не берете адрес o и сохраняете его где-то, что будет работать после возвращения f . Этого вам следует избегать - передайте shared_ptr, если вам нужно это сделать.
Прежде всего, с точки зрения функциональности ссылки в C++ точно такие же, как указатели.Единственная причина, по которой они были добавлены в язык, заключалась в том, чтобы сделать синтаксис перегрузки операторов более естественным.(Например, чтобы можно было писать a+b вместо &a+&b)
Ваши примеры кода C и C++ абсолютно не эквивалентны.Версия C вашего кода на C++ будет такой:
f(object *p){
//do something
}
int main(){
object o;
object_constructor(&o);
f(&o);
object_destructor(&o);
}
Фактически, именно такой код концептуально сгенерирует ваш компилятор C++.
Что касается вашего второго вопроса:Да, это правильный способ вызова функции f.Счетчик общего указателя не будет увеличиваться.Фактический указатель на объект будет передан, как если бы вы не использовали общий_ptr.Однако это безопасно, пока f не делает ничего странного.Просто помните, что происходит то же самое, как если бы параметр f принимал указатель вместо ссылки.Единственное отличие состоит в том, что компилятор автоматически передает адрес переменной без необходимости явного использования оператора &.
Лично мне не нравится передавать переменные по ссылке (хотя передача по константной ссылке вполне допустима).Вместо этого я предпочитаю использовать указатель, поскольку он дает понять в месте вызова, что функция, которую мы вызываем, потенциально может изменить свой аргумент (поскольку символ & виден в месте вызова).
Мир