C++17 sharedPtr vs. sharedPtr&

Gast #7234499
Lesenswert?

Hallo zusammen,

ich mache einen Onlinekurs und habe eine Frage, die ich auch mit einer 
anderen Quelle für mich nicht beantworten kann, da sie für mich die 
Selbe Frage aufwirft.
Öffentliche Onlinequelle ist
https://www.modernescpp.com/index.php/c-core-guidelines-passing-smart-pointer
und es geht mir um R34/R35

Ganz konkret um diese Statements
1
void share(std::shared_ptr<Widget> shaWid): I'm for the lifetime of the function body a shared owner of the Widget. At the beginning of the function body, I will increase the reference counter; at the end of the function, I will decrease the reference counter; therefore, the Widget will stay alive, as long as I use it.
2

3
void reseat(std::shared_ptr<Widget>& shaWid): I'm not a shared owner of the Widget, because I will not change the reference counter. I have not guaranteed that the Widget will stay alive during the execution of my function, but I can reseat the resource. A non-const lvalue reference is more like: I borrow the resource and can reseat it.

Zum reseaten könnte man doch auch machen
1
void share(std::shared_ptr<Widget> shaWid)
2
{
3
   shaWid.get() = new Widget();
4
}
oder sinngemäß, falls das so syntaktisch falsch ist.
#7234585
Lesenswert?

Daniel Larusso schrieb:
> Zum reseaten könnte man doch auch machen
>
1
> void share(std::shared_ptr<Widget> shaWid)
2
> {
3
>    shaWid.get() = new Widget();
4
> }
5
>
> oder sinngemäß, falls das so syntaktisch falsch ist.
Das ist so nicht möglich, der Zugriff auf den internen Raw-Pointer wird 
unterbunden. Es geht nur
1
void share(std::shared_ptr<Widget> & shaWid)
2
{
3
   shaWid = std::shared_ptr<Widget>( new Widget() );
4
}
deswegen muss der shared Pointer als Referenz übergeben werden. (Hier 
bin ich mir gar nicht sicher was passiert, wenn der originale 
Referenzcounter größer als 1 gewesen ist ...)

Aaaaaber: Wenn ich shared Pointer verwende, dann möchte ich eigentlich, 
dass alle mit dem selben Objekt arbeiten, und nicht das Hinz und Kunz da 
beliebig neue Objekte erzeugen und die weitergereicht werden. Die 
Weitergabe eines shared Pointer als Referenz sollte die absolute 
Ausnahme sein (für mich ist das ein Antipattern und damit schlechter 
Code).

merciless
Gast #7234751
Lesenswert?

Ist das sprechender Code?!
Ehrlich gesagt finde ich das Englisch sehr merkwürdig, denn daß eine 
Funktion sprechen kann ist mir noch nicht untergekommen.
Fachlich haben meine Vorposter schon das Richtige gesagt.
#7234898
Lesenswert?

Daniel Larusso schrieb:

> Zum reseaten könnte man doch auch machen
>
1
> void share(std::shared_ptr<Widget> shaWid)
2
> {
3
>    shaWid.get() = new Widget();
4
> }
5
>
> oder sinngemäß, falls das so syntaktisch falsch ist.

Nein. saWid ist eine Kopie! Deswegen ist das Quatsch.

Hier gelten die generellen Regeln:

Input-Parameter: per-value oder const-ref. Das Argument des Aufrufers 
kann nicht geändert werden.

input-output-Parameter: non-const-ref. Das Argument des Aufrufes soll 
geändert werden.

Das ist in jeder Schnittstelle so. Und genau das haben wir hier. Das 
"reseat" bedeutet, dass der Smart-Pointer auf ein anderes Objekt zeigen 
soll.
#7234919
Lesenswert?

Thomas W. schrieb:
> Was ist denn "reseat" ?

Dem Zeiger ein anderes Objekt unterschieben.

> Normal hätte ich gesagt, daß eine Referenz auf einen Shared-Pointer
> keine gute Idee ist.

Wilhelm M. schrieb:
> Daniel Larusso schrieb:
>
>> Zum reseaten könnte man doch auch machen
>>> void share(std::shared_ptr<Widget> shaWid)
>> {
>>    shaWid.get() = new Widget();
>> }
>>
>> oder sinngemäß, falls das so syntaktisch falsch ist.
>
> Nein. saWid ist eine Kopie! Deswegen ist das Quatsch.

Vor allem ist auch der Zeiger, den shaWid.get() zurückliefert, eine 
Kopie.
#7234926
Lesenswert?

Daniel Larusso schrieb:
> ich mache einen Onlinekurs und habe eine Frage,

Grundsätzlich kann man shared_ptr wie einen natürlichen build-in pointer 
betrachten: Also den pointer übergeben wenn man die Daten modifizieren 
will (share); einen pointer auf den pointer oder eine Referenz wenn man 
den pointer selbst ändern möchte (reseat).

Ein shared_ptr ist allerdings kein build-in pointer. Daher sollte man 
imho einen shared_ptr nur by-value (wie in share) übergeben wenn die 
ownership transferred oder geshared werden soll; ansonsten den build-in 
pointer mit get() übergeben.

https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value

Grundsätzlich bin ich kein Fan davon Argumente zu modifizieren. Statt
1
f(&p)
würde ich immer
1
p = f()
vorziehen was besser lesbar ist.

Daniel Larusso schrieb:
> Zum reseaten könnte man doch auch machen
> void share(std::shared_ptr<Widget> shaWid)
> ...
So nicht, aber ja, das geht:
1
shaWid.reset(new Widget());
Da könnte für den Aufrufer aber verwirrend sein. Würde ich niemals so 
machen.

Daniel Larusso schrieb:
> share(std::shared_ptr<Widget> shaWid):
> I'm for the lifetime of the function body a shared owner of the
> Widget. At the beginning of the function body, I will increase the
> reference counter; at the end of the function, I will decrease the
> reference counter; therefore, the Widget will stay alive, as long as I
> use it.

Das ist richtig; macht hier aber keinen Sinn (solange nicht ein anderer 
Thread darauf zugreift) weil die resource ja vom Aufrufer verwaltet wird 
und damit eh während des Aufrufs existiert.

> void reseat(std::shared_ptr<Widget>& shaWid): I'm not a shared owner of
> the Widget, because I will not change the reference counter. I have not
> guaranteed that the Widget will stay alive during the execution of my
> function, but I can reseat the resource. A non-const lvalue reference is
> more like: I borrow the resource and can reseat it.

Das ist ebenfalls nicht falsch. Da const nicht verwendet wurde 
interpretiere ich solch eine Funktion aber nicht als "borgen und kann 
ändern", sondern dass hier die Absicht vorliegt, den Pointer selbst zu 
ändern. Weniger verwirrend ist die Form p=f() wie oben geschrieben.
Gast #7239479
Lesenswert?

Dirk K. schrieb:
> Das ist so nicht möglich, der Zugriff auf den internen Raw-Pointer wird
> unterbunden. Es geht nur
>
1
> void share(std::shared_ptr<Widget> & shaWid)
2
> {
3
>    shaWid = std::shared_ptr<Widget>( new Widget() );
4
> }
5
>
> deswegen muss der shared Pointer als Referenz übergeben werden. (Hier
> bin ich mir gar nicht sicher was passiert, wenn der originale
> Referenzcounter größer als 1 gewesen ist ...)

Wieso allozieren, wenn man auch das Objekt neu konstruieren kann?
1
void share(std::shared_ptr<Widget> shaWid)
2
{
3
   *shaWid = Widget{};
4
}

https://godbolt.org/z/1Yhra3Kjz

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren