438 votes

Retourner un unique_ptr à partir de fonctions

unique_ptr<T> ne permet pas la construction de copies, mais supporte la sémantique du déplacement. Pourtant, je peux retourner un unique_ptr<T> d'une fonction et affecte la valeur renvoyée à une variable.

#include <iostream>
#include <memory>

using namespace std;

unique_ptr<int> foo()
{
  unique_ptr<int> p( new int(10) );

  return p;                   // 1
  //return move( p );         // 2
}

int main()
{
  unique_ptr<int> p = foo();

  cout << *p << endl;
  return 0;
}

Le code ci-dessus compile et fonctionne comme prévu. Alors comment se fait-il que la ligne 1 n'invoque pas le constructeur de copie et entraîne des erreurs de compilation ? Si je devais utiliser la ligne 2 au lieu de cela, il serait logique (en utilisant la ligne 2 fonctionne également, mais nous ne sommes pas tenus de le faire).

Je sais que C++0x permet cette exception pour unique_ptr puisque la valeur de retour est un objet temporaire qui sera détruit dès la sortie de la fonction, garantissant ainsi l'unicité du pointeur retourné. Je suis curieux de savoir comment cela est mis en œuvre, est-ce un cas spécial dans le compilateur ou y a-t-il une autre clause dans la spécification du langage que cela exploite ?

0 votes

Hypothétiquement, si vous implémentez une usine préférez-vous 1 ou 2 pour retourner la sortie de l'usine ? Je présume que c'est l'utilisation la plus courante de 1 parce que, avec une bonne fabrique, vous voulez que la propriété de la chose construite soit transmise à l'appelant.

7 votes

@Xharlie ? Ils passent tous les deux la propriété de la unique_ptr . Toute la question porte sur le fait que 1 et 2 sont deux façons différentes de réaliser la même chose.

0 votes

Dans ce cas, la RVO a lieu en c++0x aussi, la destruction de l'objet unique_ptr sera une fois qui est effectuée après main sort, mais pas lorsque la fonction foo sortent.

6voto

Vicky Gupta Points 131

Je voudrais mentionner un cas où vous devez utiliser std::move(), sinon il donnera une erreur. Cas : Si le type de retour de la fonction diffère du type de la variable locale.

class Base { ... };
class Derived : public Base { ... };
...
std::unique_ptr<Base> Foo() {
     std::unique_ptr<Derived> derived(new Derived());
     return std::move(derived); //std::move() must
}

Référence : https://www.chromium.org/developers/smart-pointer-guidelines

0 votes

Merci de l'avoir signalé ! !!

0 votes

Mais si je supprime std::move, il n'y a pas d'erreur à la compilation. Le compilateur essaiera d'appeler le constructeur de move si le constructeur de copy n'est pas appelable. Donc le std::move ici peut être redondant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X