50 votes

c ++ {* this} à l'intérieur des accolades

Le code suivant compile bien:

 g++ -std=c++11 test.cpp -Wall -Wextra -Wfatal-errors && ./a.out
 

Cependant, si je supprime les accolades de {*this} et utilise *this place, je ferai face à une erreur:

erreur: utilisation de la fonction supprimée 'Obj :: Position :: Position (Obj :: Position &&)'

Quelle est la différence entre {*this} et *this ?

 class Obj
{
    template<bool> friend class Position;

    double data;
public:
    class Position
    {
        const Obj& ref;
    public:
        inline Position(const Obj& ref): ref(ref){}
        inline Position(Position const &) = delete;
        inline Position(Position &&) = delete;
    };
    inline Obj(){}
    inline Obj(const double &data): data(data){}
    inline auto get_pos() const-> Position{return {*this};} /* <--- here */
    inline auto get_pos()-> Position{return {*this};}
};

int main()
{
    return 0;
}
 

37voto

Praetorian Points 47122

Lorsque les accolades sont présents, vous êtes copie de la liste d'initialisation de la valeur de retour, pas de copier/déplacer constructeur est impliqué. La valeur de retour est construit sur place à l'aide de l' Position(const Obj&) constructeur.

Notez que le code ne compile même avec les accolades si vous faites l' Position(const Obj&) constructeur explicit parce que copie de la liste d'initialisation ne permet pas explicite des constructeurs pour être appelé.

Si vous omettez les accolades, alors sémantiquement temporaire Position objet est construit à l'intérieur de la fonction, et la valeur de retour est construit à partir que temporaire. Dans la pratique, la plupart des implémentations d'éluder le déplacement de la construction, mais il nécessite toujours une solution viable constructeur de déplacement à être présent, ce qui n'est pas le cas ici, car il a été explicitement supprimé. C'est pour cette raison que votre code ne compilera pas sans croisillons.

À l'aide d'un C++17 compilateur, votre code ne compile même sans les accolades en raison de la garantie des copier-élision.

17voto

Tobias Points 3120

La différence entre les deux est vraiment très subtile. C++11 introduit la fonctionnalité de liste d'initialisation (aussi parfois appelée accolade de l'initialisation):

Avant C++11, lorsque vous voulez par défaut-construction de l'objet et de l' o de type Obj et de construire un Position p de o, vous avez eu à l'écrire

Obj o;              // default construct o
Obj::Position p(o); // construct p using Position(Obj const&)

Une erreur commune pour les débutants (surtout avec un Java de fond) afin d'essayer d'écrire ceci:

Obj o();            // mistake: declares a function o returning an Obj
Obj::Position p(o); // error: no constructor takes a function 

La première ligne déclare une fonction, et la deuxième, on essaie de créer un Position à l'aide d'un constructeur qui prend un pointeur de fonction en argument. Afin de disposer d'un uniforme de l'initialiseur de la syntaxe de C++11 introduit initialisation de la liste:

Obj oo{};             // new in C++11: default construct o of type Obj
Obj::Position p1(oo); // possible before (and after) C++11
Obj::Position p2{oo}; // new in C++11: construct p2 using Position(Obj const&)

Cette nouvelle syntaxe fonctionne également en return-états, ce qui conduit à la réponse de votre question: la différence entre return {*this}; et return *this; , c'est que l'ancien initialise la valeur de retour directement à partir de *this, tandis que le second se convertit *this temporairement Position objet, puis initialise la valeur de retour indirectement à partir de ce temporaire, qui échoue en raison à la fois la copie et déplacement-constructeur ont été explicitement supprimé.

Comme les précédentes affiches ont noté, la plupart des compilateurs éluder ces objets temporaires parce qu'ils ne sont pas vraiment utile pour quoi que ce soit; mais cela n'est possible que si ils pourraient être utilisés dans la théorie, soit parce que d'une copie ou d'un constructeur de déplacement est disponible. Parce que cela conduit à beaucoup de confusion (pourquoi ai-je besoin des accolades autour de mon retour? est le compilateur va éluder la copie ou pas?), C++17 fait disparaître ces inutiles temporaires, et initialise la valeur de retour directement dans les deux cas (return {*this}; et return *this).

Vous pouvez essayer ceci à l'aide d'un compilateur qui prend en charge le C++17. Dans clang 4.0 ou gcc 7.1, vous pouvez passer --std=c++1z, et de votre code devrait compiler amende avec ou sans bretelles.

13voto

isp-zax Points 2226

C'est un bon! C'est parce qu' return {...} signifie "renvoyer un objet de la fonction de type de retour de la initialisé avec la liste d'initialisation ...".

Liste des initialiseurs sont décrites plus en détail ici:

http://en.cppreference.com/w/cpp/language/list%20initialization

Donc, la différence est qu' {*this} des appels ceci:

inline Position(const Obj& ref): ref(ref){}

Alors qu' *this tente de convertir Obj& de Position en utilisant explicitement supprimé opérateurs d'affectation (avant C++11, ils devraient être apportées private, et vous obtenez encore plus de confusion, message d'erreur si la liste des initialiseurs serait disponible...):

inline Position(Position const &) = delete;
inline Position(Position &&) = delete;

-2voto

Sandro Points 37

franchement, à l'aide de votre classe et les suivants():

int main()
{
    Obj o1;
    cout<<"get position"<<'\n';
    Obj::Position pos= o1.get_pos();


    cout.flush();
    return 0;
}

il ne veut pas compiler (gcc/mingw) dans les deux cas(-std=c++14), avec ou sans accolades et il se plaint de manque de Position(Position&&) constructeur, qui est supprimé. Il est raisonnable, car il semble que dans les deux cas d'une construction temporaire, le retour de l'objet est effectuée, qui, ensuite, il doit être déplacé vers la destination. Ce qui est impossible en tant que constructeur de déplacement est supprimé. À l'inverse, l'aide -std=c++17 drapeau qu'il compile dans les deux cas (avec ou sans accolades) que, plus probablement, nous sommes frapper le rendement garanti,-optimisation de la valeur des c++17. Espérons que cette aide.

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