2011-04-28 2 views
2

Le code suivantComment puis-je interdire les appels à la fonction membre const d'un objet rvalue dans C++ 2011?

#include <vector> 
#include <string> 
#include <iostream> 

std::string const& at(std::vector<std::string> const& n, int i) 
{ 
    return n[i]; 
} 

std::vector<std::string> mkvec() 
{ 
    std::vector<std::string> n; 
    n.push_back("kagami"); 
    n.push_back("misao"); 
    return n; 
} 

int main() 
{ 
    std::string const& s = at(mkvec(), 0); 
    std::cout << s << std::endl; // D'oh! 
    return 0; 
} 

peut conduire à l'accident parce que le vecteur d'origine est déjà détruit là. En C++ 2011 (C++ 0x) après rvalue référence est introduit dans une fonction supprimé déclaration peut être utilisée pour interdire complètement les appels à at si l'argument vecteur est un rvalue

std::string const& at(std::vector<std::string>&&, int) = delete; 

Cela semble bon, mais le code suivant encore causer accident

int main() 
{ 
    std::string const& s = mkvec()[0]; 
    std::cout << s << std::endl; // D'oh! 
    return 0; 
} 

parce que les appels à la fonction de membre operator [] (size_type) const d'un objet rvalue est encore autorisée. Est-ce que je peux interdire ce genre d'appels?

CORRECTIF:

Les exemples ci-dessus n'est pas ce que je faisais dans des projets concrets. Je me demande si C++ 2011 toute fonction de soutien de membre admissible comme

class A { 
    void func() rvalue; // Then a call on an rvalue object goes to this overload 
    void func() const; 
}; 

CORRECTIF:

Il est grand, mais je pense que la norme C de va trop loin à cette fonction. Quoi qu'il en soit, j'ai le code suivant compilé sur clang ++ 2.9

#include <cstdio> 

struct A { 
    A() {} 

    void func() & 
    { 
     puts("a"); 
    } 

    void func() && 
    { 
     puts("b"); 
    } 

    void func() const & 
    { 
     puts("c"); 
    } 
}; 

int main() 
{ 
    A().func(); 
    A a; 
    a.func(); 
    A const b; 
    b.func(); 
    return 0; 
} 

Merci beaucoup!

Répondre

6

Non, et vous ne devriez pas. Comment dois-je faire std::cout << at(mkvec(), 0) << std::endl;, une chose parfaitement raisonnable, si vous m'avez interdit d'utiliser at() sur les temporaires?

Le stockage de références à des temporaires n'est malheureusement qu'un problème pour les programmeurs C++.


Pour répondre à votre nouvelle question, oui, vous pouvez le faire:

class A { 
    void func() &; // lvalues go to this one 
    void func() &&; // rvalues go to this one 
}; 

A a; 
a.func(); // first overload 

A().func(); // second overload 
+0

Je J'ai toujours trouvé cette référence contraignante. Cela a dû être une bonne idée pour commencer, et bien sûr c'est pratique à certains moments, mais son potentiel de destruction est incroyable et même l'inspection du code méticuleux peut ne pas le détecter ...:/ –

+0

Merci pour cet indice, mais j'ai compilé erreurs sur g ++ 4.6.0. Pouvez-vous me dire quel compilateur peut gérer cela? – neuront

+0

Si vous rendez public les surcharges 'func', les versions récentes de clang géreront cet exemple. –

-1

Juste une idée:

Pour désactiver la copie constructeur sur le vecteur d'une certaine manière.

vector (const vector<T,Allocator>& x); 

La copie implicite de tableaux n'est pas une bonne chose de toute façon. (Se demandant pourquoi les auteurs de la STL ont décidé de définir ces cteur du tout)

Il résoudra les problèmes comme vous l'avez mentionné et comme un bonus vous forcer à utiliser version plus efficace de votre fonction:

void mkvec(std::vector<std::string>& n) 
{ 
    n.push_back("kagami"); 
    n.push_back("misao"); 
} 
+1

Suggérez-vous sérieusement qu'il modifie sa bibliothèque standard pour rendre le vecteur non-copy-constructable? Ou est-ce que je vous trompe? Parce que c'est la suggestion la plus stupide que j'ai jamais entendue. –

+1

Votre version de 'mkvec' n'est pas nécessairement plus efficace, consultez RVO. – GManNickG

+0

La fonction 'mkvec()' est parfaitement bien, oui! Merci à ** Return-Value-Optimization **, et en C++ 0x encore plus, grâce aux RValues, oui. S'il vous plaît oui, écrivez le code comme ceci, c'est RAII, concis, sûr et rapide. Mais, bien sûr 'string & s = mkvec() [0]' explose, c'est correct. Vous l'avez nommé juste 'mk ...' ** fait ** quelque chose. N'obtenez pas un ref sur quelque chose que vous venez de faire * - c'est le problème. Si vous l'aviez appelé 'getvec()', * alors * je m'attendrais à ce que 'string & s = getvec() [0]' soit correct. Mais 'string & s = mkvec() [0]' est autorisé à échouer :-) – towi

Questions connexes