Forum: PC-Programmierung C++17 sharedPtr vs. sharedPtr&


von Daniel Larusso (Gast)


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.

von Thomas W. (goaty)


Lesenswert?

Was ist denn "reseat" ?
Normal hätte ich gesagt, daß eine Referenz auf einen Shared-Pointer 
keine gute Idee ist.

von Dirk K. (merciless)


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

von loeti2 (Gast)


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.

von Wilhelm M. (wimalopaan)


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.

von Rolf M. (rmagnus)


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.

von Mikro 7. (mikro77)


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.

von Markus (Gast)


Lesenswert?

Daniel Larusso schrieb:
> ich mache einen Onlinekurs

Welcher Kurs ist das und welche Erfahrungen hast Du damit gemacht?

von CppX (Gast)


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

von Wilhelm M. (wimalopaan)


Lesenswert?

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

Blödsinn (s.o.)

von Bierbaron (Gast)


Lesenswert?

Man ist C++ ein unverständlicher Schrott geworden

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.