Передача общих указателей в качестве аргументов

Если я объявлю объект, завернутый в общий указатель:

std::shared_ptr<myClass> myClassObject(new myClass());

тогда я хотел передать это как аргумент методу:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

Вышесказанное просто увеличивает счетчик ссылок shared_pt и все круто? Или это оставляет висячий указатель?

Вы все еще должны это делать?

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

Я думаю, что 2-й способ может быть более эффективным, поскольку он должен копировать только 1 адрес (в отличие от всего интеллектуального указателя), но 1-й способ кажется более читабельным, и я не ожидаю увеличения ограничений производительности. Я просто хочу убедиться, что в этом нет ничего опасного.

Спасибо.

 ildjarn31 мая 2012 г., 04:09
@ SteveH: вся цель интеллектуальных указателей состоит в том, чтобы справиться с обычными проблемами владения объектами - если у вас их нет, вы не должны в первую очередь использовать интеллектуальные указатели. ;-] Относительноshared_ptr<> конкретно тыmust передать по значению, чтобы фактически разделить собственность.
 Captain Obvlious31 мая 2012 г., 04:01
const std::shared_ptr<myClass>& arg1
 ildjarn31 мая 2012 г., 04:05
@ SteveH: Это не так, но почему ваша функция должна навязывать специальную семантику владения объектом своим вызывающим, если она на самом деле не нужна? Ваша функция не делает ничего, что было бы лучше, чемvoid DoSomething(myClass& arg1).
 R. Martinho Fernandes31 мая 2012 г., 05:31
Не связано: в общем,std::make_shared не только эффективнее, но иsafer чемstd::shared_ptr конструктор.
 ildjarn31 мая 2012 г., 04:03
Второй путь сломан, первый идиоматичен, если вам действительно нужна ваша функция для совместного владения. Но делает лиDoSomething действительно нужно делиться собственностью? Похоже, вместо этого нужно просто взять ссылку ...

Ответы на вопрос(4)

Решение Вопроса

I want to pass a shared pointer to a function. Can you help me with that?

Конечно, я могу помочь вам с этим. Я предполагаю, что у вас есть некоторое понимание семантики владения в C ++. Это правда?

Yeah, I'm reasonably comfortable with the subject.

Хорошо.

Хорошо, я могу думать только о двух причинахshared_ptr аргумент:

The function wants to share ownership of the object; The function does some operation that works specifically on shared_ptrs.

Какой из них вас интересует?

I'm looking for a general answer, so I'm actually interested in both. I'm curious about what you mean in case #2, though.

Примеры таких функций включаютstd::static_pointer_castпользовательские компараторы или предикаты. Например, если вам нужно найти все уникальные shared_ptr из вектора, вам нужен такой предикат.

Ah, when the function actually needs to manipulate the smart pointer itself.

Именно так.

In that case, I think we should pass by reference.

Да. И если он не меняет указатель, вы хотите передать по константной ссылке. Нет необходимости копировать, так как вам не нужно делиться собственностью. Это другой сценарий.

Ok, got it. Let's talk about the other scenario.

Тот, где вы разделяете право собственности? Хорошо. Как вы делитесь собственностью сshared_ptr?

By copying it.

Тогда функция должна будет сделать копиюshared_ptr, правильный?

Obviously. So I pass it by a reference to const and copy to a local variable?

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

Good point. I must remember that "Want Speed? Pass by Value." article more often.

Wait, what if the function stores the shared_ptr in a member variable, for example? Won't that make a redundant copy?

Функция может просто переместитьshared_ptr аргумент в его хранилище. Перемещениеshared_ptr дешевый, потому что он не меняет счетчика ссылок.

Ah, good idea.

But I'm thinking of a third scenario: what if you don't want to manipulate the shared_ptr, nor to share ownership?

В таком случае,shared_ptr совершенно не имеет отношения к функции. Если вы хотите манипулировать pointee, возьмите pointee и позвольте звонящим выбрать, какую семантику владения они хотят.

And should I take the pointee by reference or by value?

Обычные правила применяются. Умные указатели ничего не меняют.

Pass by value if I'm going to copy, pass by reference if I want to avoid a copy.

Правильно.

Hmm. I think you forgot yet another scenario. What if I want to share ownership, but only depending on a certain condition?

Ах, интересный крайний случай. Я не ожидаю, что это случится часто. Но когда это происходит, вы можете либо передать по значению и проигнорировать копию, если она вам не нужна, либо перейти по ссылке и сделать копию, если вам это нужно.

I risk one redundant copy in the first option, and lose a potential move in the second. Can't I eat the cake and have it too?

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

I think that covers all the possible scenarios. Thank you very much.

 31 мая 2012 г., 05:17
номинация наc++-faq тег
 07 июн. 2012 г., 02:41
Некоторые примеры кода были бы хорошими
 31 мая 2012 г., 05:14
+1, классно. Пропавшие звезды от руки, хотя. :П
 08 июн. 2012 г., 14:20
Поскольку проза похож на «Означает ли это, что я» передам его по ссылке на const, чтобы сделать копию? Нет, это пессимизация смущает начинающего. Переход по ссылке на const не делает копию.
 07 июн. 2012 г., 12:14
@Jon: для чего? Это все о том, что я должен делатьA или я должен сделатьB, Я думаю, что мы все знаем, как передавать объекты по значению / ссылке, нет?

Я думаю, что люди излишне боятся использовать необработанные указатели в качестве параметров функции. Если функция не собирается хранить указатель или иным образом влиять на его время жизни, необработанный указатель работает так же хорошо и представляет наименьший общий знаменатель. Рассмотрим, например, как вы могли бы пройтиunique_ptr в функцию, которая принимаетshared_ptr в качестве параметра, по значению или по константной ссылке?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());

Необработанный указатель как параметр функции не мешает вам использовать умные указатели в вызывающем коде, где это действительно важно.

 31 мая 2012 г., 05:47
@ Xeo, ты прав - это было бы еще лучше. Иногда вам нужно учесть возможность указателя NULL.
 31 мая 2012 г., 05:43
Если вы используете указатель, почему бы просто не использовать ссылку?DoSomething(*a_smart_ptr)
 03 окт. 2013 г., 01:07
@AndreasMagnusson: Соглашение «указатель как выходной параметр» может дать ложное ощущение безопасности при работе с указателями, переданными из другого источника. Потому что в этом случае вызов забавный (x), и * x изменяется, и у источника нет & amp; x, чтобы предупредить вас.
 29 авг. 2012 г., 14:13
Если у вас есть соглашение об использовании необработанных указателей в качестве выходных параметров, в вызывающем коде легче обнаружить, что переменная может измениться, например: сравнитьfun(&x) вfun(x), В последнем примереx может быть передано по значению или как конст. Это, как указано выше, также позволит вам пройтиnullptrесли вы не заинтересованы в выводе ...

Да, вся идея о shared_ptr & lt; & gt; в том, что несколько экземпляров могут содержать один и тот же необработанный указатель, и основная память будет освобождена только при наличии последнего экземпляра shared_ptr & lt; & gt; уничтожен

Я бы не указывал на shared_ptr & lt; & gt; поскольку это побеждает цель, поскольку вы теперь снова имеете дело с raw_pointers.

Передача по значению в вашем первом примере безопасна, но есть и лучшая идиома. Когда это возможно, используйте константную ссылку - я бы сказал, да, даже когда дело касается умных указателей. Ваш второй пример не совсем разбит, но он очень!???, Глупо, ничего не достигая и побеждая часть смысла умных указателей, и оставит вас в глючном мире боли, когда вы попытаетесь разыменовать и модифицировать вещи.

 31 мая 2012 г., 04:21
... если, с другой стороны, функции не нужно продлевать время жизни объекта, то вы можете просто удалитьshared_ptr с интерфейса и передать равнину (const) ссылка на указанный объект.
 31 мая 2012 г., 04:20
@ildjarn: передача константной ссылки - это нормально в этом случае. Оригиналshared_ptr вызывающего абонента гарантированно переживет вызов функции, поэтому функция безопасна при использованииshared_ptr<> const &, Если необходимо сохранить указатель на более позднее время, его нужно будет скопировать (на этом этапе необходимо сделать копию, а не хранить ссылку), но при этом нет необходимости нести расходы на копирование.unless тебе нужно это сделать. Я бы пошел для передачи постоянной ссылки в этом случае ....
 31 мая 2012 г., 04:26
@ Дэвид: Что делать, если ваш пользователь API не используетshared_ptr<> начать с? Теперь ваш API на самом деле просто боль в шее, так как он заставляет вызывающего пользователя бессмысленно изменять семантику времени жизни своего объекта, просто чтобы использовать его. Я не вижу в этом ничего стоящего, кроме как сказать, что "это ничего не повредит технически". Я не вижу ничего противоречивого в том, что "если вам не нужно совместное владение, не используйте"shared_ptr<>& APOS ;.
 31 мая 2012 г., 04:21
@ Дэвид: & quot;Passing a constant reference is fine in this case.& Quot; Не в каком-либо нормальном API - почему API требует умного типа указателя, который он даже не использует, а не просто использует обычную константную ссылку? Это почти так же плохо, как отсутствие правильности. Если ваша точка зрения такова, что технически это никому не вредит, то я, конечно, согласен, но я не думаю, что это правильно.
 31 мая 2012 г., 04:13
Никто не защищает передачу по указателю, если вы имеете в виду необработанный указатель. Передача по ссылке, если нет права собственности, безусловно, идиоматична. Дело в том, что в отношенииshared_ptr<> конкретно, что тыmust сделать копию, чтобы фактически разделить собственность; если у вас есть ссылка или указатель наshared_ptr<> тогда вы ничего не передаете и подвержены тем же проблемам, что и обычные ссылки или указатели.

Ваш ответ на вопрос