Ce code est ce que je veux faire:
Tony& Movie::addTony()
{
Tony *newTony = new Tony;
std::unique_ptr<Tony> tony(newTony);
attachActor(std::move(tony));
return *newTony;
}
Je me demande si je pourrais le faire à la place:
Tony& Movie::addTony()
{
std::unique_ptr<Tony> tony(new Tony);
attachActor(std::move(tony));
return *tony.get();
}
Mais *tony.get()
sera-t-il le même pointeur ou nul? Je sais que je pourrais vérifier, mais quelle est la chose standard à faire?
Non, vous ne pouvez pas faire ça à la place. Déplacer le unique_ptr
l'annule. Sinon, ce ne serait pas unique. Je suppose bien sûr que attachActor
ne fait pas quelque chose de stupide comme ceci:
attachActor(std::unique_ptr<Tony>&&) {
// take the unique_ptr by r-value reference,
// and then don't move from it, leaving the
// original intact
}
Section 20.8.1, paragraphe 4.
De plus, u (l'objet unique_ptr) peut, sur demande, transférer la propriété à un autre pointeur unique u2. À l'issue d'un tel transfert, les conditions suivantes sont remplies:
- u2.p est égal à u.p avant transfert,
- .p est égal à nullptr, et
- si l'état maintenu avant le transfert u.d, cet état a été transféré vers u2.d.
La norme dit (§ 20.8.1.2.1 ¶ 16, souligné par nous) que le constructeur de déplacement de std::unique_ptr
unique_ptr(unique_ptr&& u) noexcept;
Construit un
unique_ptr
En transfert de propriété deu
à*this
.
Par conséquent, après avoir déplacé-construit l'objet temporaire qui est passé comme argument à attachActor
de votre tony
, tony
ne possède plus l'objet et donc tony.get() == nullptr
. (C'est l'un des rares cas où la bibliothèque standard fait des affirmations sur l'état d'un objet éloigné.)
Cependant, le désir de retourner la référence peut être satisfait sans recourir à des pointeurs nus new
et bruts.
Tony&
Movie::addTony()
{
auto tony = std::make_unique<Tony>();
auto p = tony.get();
attachActor(std::move(tony));
return *p;
}
Ce code suppose que attachActor
ne laissera pas tomber son argument sur le sol. Sinon, le pointeur p
se balancerait après que attachActor
aura return
édité. Si cela ne peut pas être invoqué, vous devrez repenser votre interface et utiliser des pointeurs partagés à la place.
std::shared_ptr<Tony>
Movie::addTony()
{
auto tony = std::make_shared<Tony>();
attachActor(tony);
return tony;
}