Question

désolé pour cette longue question, mais j'essaie d'être aussi clair que possible. Cela fait suite en quelque sorte ma précédente question sur chaînes en C ++ . J'essaie de comprendre comment je pouvais revenir std :: string à partir d'une fonction sans allocations de mémoire redondantes, sans compter sur NRVO . Les raisons pour lesquelles je ne veux pas compter sur NRVO sont:

  • il est pas pris en charge par le compilateur que nous utilisons actuellement
  • même quand il est pris en charge ne pourrait pas toujours être activé en mode débogage
  • il pourrait échouer dans certains cas ( exemple )

S'il vous plaît noter que je besoin d'un C ++ 03 solution compatible (pas de références C ++ 0x rvalue donc, malheureusement ...)

La façon la plus simple faire est passe par référence et ne std :: swap, comme ceci

void test(std::string& res)
{
    std::string s;
    //...
    res.swap(s);
}

Mais il est plus naturel et souvent plus commode de retourner par la valeur de passage par référence, donc ce que je veux atteindre est le suivant:

std::string test()
{
    std::string s;
    //...
    return SOMETHING(s);
}

Idéalement, il serait tout simplement faire un swap avec la « valeur de retour », mais je ne vois pas comment faire cela en C ++. Il y a déjà auto_ptr qui ne se déplace au lieu de copier, et je pouvais utiliser auto_ptr<string>, mais je voudrais éviter d'allouer dynamiquement l'objet chaîne elle-même.

Mon idée est de quelque sorte « tag » un objet de chaîne qui est retournée d'une fonction de permis déplacer ses données lorsqu'un constructeur de copie est appelée sur le retour. Donc, je me suis retrouvé avec ce code, qui fait exactement ce que je veux:

struct Str
{
    struct Moveable
    {
        Str & ref;
        explicit Moveable(Str & other): ref(other) {}
    };

    Str() {}
    Str(const std::string& other) : data(other) {} // copy
    Str(Moveable& other) { data.swap(other.ref.data); } // move

    Moveable Move()
    {
        return Moveable(*this);
    }

    std::string data;
};

Str test()
{
    Str s;
    //...
    return s.Move(); // no allocation, even without NRVO
}

Alors ... Est-ce que tout cela a du sens, ou il y a des problèmes graves que je me manque? (Je ne sais pas s'il n'y a pas de problème à vie par exemple). Peut-être que vous avez déjà vu une telle idée dans une bibliothèque (livre, article ...), et pourrait me donner une référence à elle?

EDIT: Comme @rstevens remarqué, ce code est MSVC spécifique et ne sera pas compilé sous g ++ qui ne aime pas la non-const temporaire. Cette un problème, mais supposons que cette mise en œuvre est MSVC spécifique.

Était-ce utile?

La solution

La mise en œuvre des utilisations de stimuler l'émulation interne déplacer la sémantique pour les bibliothèques comme Boost.Thread . Vous voudrez peut-être regarder la mise en œuvre et faire quelque chose de similaire.

Modifier il est en fait un développement actif d'une bibliothèque Boost.Move , de sorte que vous pouvez déjà commencer à l'utiliser.

Autres conseils

Avez-vous vérifié ce code sur g ++?

Depuis que vous appelez Str (mobile et) avec un objet temporaire (celui retourné par s.Move ())

Ce n'est pas conforme à la norme de et non pris en charge par g ++. Il est soutenu par MSVC! (MS appelle cela une fonction ...).

Avez-vous déjà déterminé que le retour en valeur est un problème de performance dans votre application? Cela semble aller comme moyen le plus facile simple / et lorsque vous passez à un compilateur plus moderne, vous pouvez utiliser des références rvalue.

Je ne peux pas répondre à la question concernant l'ordre de destruction de s vs la référence du Movable. Vous pouvez, pour votre compilateur, le code mis dans les différents constructeurs et destructeurs de voir ce que l'ordre est. Même si cela semble ok, je serais toujours envisager d'utiliser l'un des modèles normaux que vous avez décrit, mais il suffit d'éviter toute confusion du lecteur et à briser éventuellement sur un compilateur alternatif.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top