Vraag Unieke_ptr doorgeven aan functies


Ik probeer een aantal bestaande codes te "moderniseren".

  • Ik heb een klasse die momenteel een ledenvariabele "Device * device_" heeft.
  • Het gebruikt nieuw om een ​​instantie in een initialisatiecode te maken en heeft een "verwijder apparaat_" in het destructoire.
  • Lid functies van deze klasse oproep veel andere functies die een Device * als parameter gebruiken.

Dit werkt goed, maar om mijn code te "moderniseren", dacht ik dat ik de variabele moest veranderen om te definiëren als "std::unique_ptr<Device> device_" en verwijder de expliciete oproep om te verwijderen, waardoor de code veiliger en over het algemeen beter is.

Mijn vraag is dit -

  • Hoe moet ik dan de apparaat_ variabel voor alle functies die het als parameter nodig hebben?

Ik kan .get bellen om de onbewerkte aanwijzer in elke functieaanroep te krijgen. Maar dat lijkt lelijk en verspilt een aantal redenen om een ​​unique_ptr in de eerste plaats te gebruiken.

Of ik kan veranderen elk functie zodat in plaats van een parameter van het type "Device *" te nemen, nu een parameter van het type "std :: unique_ptr &" nodig is. Wat (voor mij) de functieprototypes enigszins verbloemt en ze moeilijk leesbaar maakt.

Wat is de beste werkwijze hiervoor? Heb ik andere opties gemist?


46
2018-03-14 09:41


oorsprong


antwoorden:


In Modern C ++ -stijl, er zijn twee sleutelbegrippen:

  • Eigendom
  • ongeldigheid

Eigendom gaat over de eigenaar van een object / resource (in dit geval een instantie van Device). De verschillen std::unique_ptr, boost::scoped_ptr of std::shared_ptr gaat over eigendom.

ongeldigheid is echter veel eenvoudiger: het geeft alleen aan of een bepaald object al dan niet nul is en niets geeft om iets anders, en zeker niet om eigenaarschap!


Jij was rechts om de implementatie van je klas naar toe te verplaatsen unique_ptr (in het algemeen), hoewel u misschien een slimme aanwijzer met deep-copy-semantiek wilt als uw doel is om een ​​PIMPL te implementeren.

Dit geeft duidelijk aan dat jouw klas de enige verantwoordelijke is voor dit stukje geheugen en netjes omgaat met alle verschillende manieren waarop het geheugen anders zou kunnen lekken.


Aan de andere kant, de meeste gebruikers van de middelen kon het niet schelen over zijn eigendom.

Zolang een functie geen verwijzing naar een object bewaart (sla het op in een kaart of iets dergelijks), is het enige dat telt dat de levensduur van het object de duur van de functieaanroep overschrijdt.

Het kiezen van de parameter is dus afhankelijk van de mogelijke parameter ongeldigheid:

  • Nooit nul? Pass a referentie
  • Mogelijk nul? Pass a wijzer, een eenvoudige bare pointer of een pointer-achtige klasse (met een trap op nul bijvoorbeeld)


44
2018-03-14 10:31



Het hangt er echt van af. Als een functie eigenaar van de unique_ptr moet worden, moet de handtekening een unique_ptr<Device> bv waarde en de beller zou dat moeten doen std::move de aanwijzer. Als eigendom geen probleem is, zou ik de onbewerkte aanwijzerhandtekening behouden en de aanwijzer unique_ptr gebruiken get(). Dit is niet lelijk als de functie in kwestie neemt eigendom niet over.


14
2018-03-14 09:50



Ik zou gebruiken std::unique_ptr const&. Als u een niet-const-referentie gebruikt, krijgt de opgeroepen functie de mogelijkheid om uw aanwijzer opnieuw in te stellen.
Ik denk dat dit een leuke manier is om uit te drukken dat je opgeroepen functie de aanwijzer kan gebruiken, maar niets anders.
Dus voor mij zal dit de interface gemakkelijker te lezen maken. Ik weet dat ik niet moet rondrennen met een aanwijzer die aan mij is doorgegeven.


7
2018-03-14 09:47



De beste werkwijze is waarschijnlijk niet te gebruiken std::unique_ptr in dit geval, hoewel het ervan afhangt. (Over het algemeen zou je niet meer dan één raw moeten hebben aanwijzer naar een dynamisch toegewezen object in een klasse. Hoewel dit hangt ook af.) Het enige dat je in dit geval niet wilt doen is rondvliegen std::unique_ptr (en zoals je hebt gemerkt, std::unique_ptr<> const& is een beetje onpraktisch en versluierd). Als dit is de enige dynamisch toegewezen aanwijzer in het object, ik zou het gewoon doen met de onbewerkte aanwijzer en de delete in de destructor. Als er zijn verschillende van dergelijke verwijzingen, zou ik overwegen om ze allemaal naar een te degraderen afzonderlijke basisklasse (waar ze nog steeds als basis kunnen dienen).


2
2018-03-14 09:57



Dat is misschien niet haalbaar voor u, maar een vervanging van elke gebeurtenis Device* door const unique_ptr<Device>& is een goed begin.

Je kunt natuurlijk niet kopiëren unique_ptrs en je wilt het niet verplaatsen. Vervangen door een verwijzing naar unique_ptr laat het lichaam van de bestaande functies 'lichamen blijven werken.

Nu is er een valstrik, je moet langskomen const & om te voorkomen dat callees het doet unique_ptr.reset() of unique_ptr().release(). Merk op dat dit nog steeds een aanpasbare aanwijzer naar het apparaat doorgeeft. Met deze oplossing hebt u geen gemakkelijke manier om een ​​aanwijzer of verwijzing naar een door te geven const Device.


1
2018-03-14 09:49