web-dev-qa-db-fra.com

Pourquoi est-il possible de renvoyer un vecteur de fonction?

Veuillez considérer ce code. J'ai vu ce type de code plusieurs fois. words est un vecteur local. Comment est-il possible de le renvoyer d'une fonction? Pouvons-nous garantir qu'il ne mourra pas?

 std::vector<std::string> read_file(const std::string& path)
 {
    std::ifstream file("E:\\names.txt");

    if (!file.is_open())
    {
        std::cerr << "Unable to open file" << "\n";
        std::exit(-1);
    }

    std::vector<string> words;//this vector will be returned 
    std::string token;

    while (std::getline(file, token, ','))
    {
        words.Push_back(token);
    }

    return words;
}
106
Pranit Kothari

Pouvons-nous garantir qu'il ne mourra pas?

Tant qu'il n'y a pas de référence renvoyée, c'est parfaitement correct de le faire. words sera déplacé vers la variable recevant le résultat.

La variable locale sera hors de portée. après avoir été déplacé (ou copié).

65

Pré C++ 11:

La fonction ne renverra pas la variable locale mais plutôt une copie de celle-ci. Votre compilateur peut toutefois effectuer une optimisation sans qu'aucune action de copie réelle ne soit effectuée.

Voir cette question & réponse pour plus de détails

C++ 11:

La fonction déplacera la valeur, voir cette réponse pour plus de détails

104
Tim Meyer

Je pense que vous faites référence au problème en C (et C++) selon lequel le retour d'un tableau à partir d'une fonction n'est pas autorisé (ou du moins ne fonctionnera pas comme prévu) - c'est parce que le retour du tableau le sera (si vous l'écrivez dans la forme simple) renvoie un pointeur sur le tableau actuel de la pile, qui est ensuite rapidement supprimé lorsque la fonction est renvoyée.

Mais dans ce cas, cela fonctionne car le std::vector est une classe et les classes, comme les structures, peuvent (et seront) être copiées dans le contexte de l'appelant. [En fait, la plupart des compilateurs optimiseront ce type de copie en utilisant quelque chose appelé "Optimisation de la valeur de retour", introduite spécifiquement pour éviter de copier des objets volumineux quand ils sont renvoyés d'une fonction, mais c'est une optimisation, et du point de vue des programmeurs, se comporte comme si le constructeur d'assignation était appelé pour l'objet]

Tant que vous ne renvoyez pas de pointeur ou de référence à quelque chose qui se trouve dans la fonction retournée, tout va bien.

24
Mats Petersson

Pour bien comprendre le comportement, vous pouvez exécuter ce code:

#include <iostream>

class MyClass
{
  public:
    MyClass() { std::cout << "run constructor MyClass::MyClass()" << std::endl; }
    ~MyClass() { std::cout << "run destructor MyClass::~MyClass()" << std::endl; }
    MyClass(const MyClass& x) { std::cout << "run copy constructor MyClass::MyClass(const MyClass&)" << std::endl; }
    MyClass& operator = (const MyClass& x) { std::cout << "run assignation MyClass::operator=(const MyClass&)" << std::endl; }
};

MyClass my_function()
{
  std::cout << "run my_function()" << std::endl;
  MyClass a;
  std::cout << "my_function is going to return a..." << std::endl;
  return a;
}

int main(int argc, char** argv)
{
  MyClass b = my_function();

  MyClass c;
  c = my_function();

  return 0;
}

La sortie est la suivante:

run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run constructor MyClass::MyClass()
run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run assignation MyClass::operator=(const MyClass&)
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()
12
Caduchon