web-dev-qa-db-fra.com

Qu'arrive-t-il à unique_ptr après std :: move ()?

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?

24
user3496846

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.

27
Benjamin Lindley

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é de u à *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;
}
11
5gon12eder