4

Je compilé l'exemple suivant:mettre en œuvre un C++ opérateur incrément postfix

#include <iostream> 
#include <iterator> 
using namespace std; 

class myiterator : public iterator<input_iterator_tag, int> 
{ 
    int* p; 
public: 
    myiterator(int* x) :p(x) {} 
    myiterator(const myiterator& mit) : p(mit.p) {} 
    myiterator& operator++() {++p;return *this;} 
    myiterator& operator++(int) {myiterator tmp(*this); operator++(); return tmp;} 
    bool operator==(const myiterator& rhs) {return p==rhs.p;} 
    bool operator!=(const myiterator& rhs) {return p!=rhs.p;} 
    int& operator*() {return *p;} 
}; 

int main() { 
    int numbers[]={10,20,30,40,50}; 
    myiterator beginning(numbers); 
    myiterator end(numbers+5); 
    for (myiterator it=beginning; it!=end; it++) 
     cout << *it << " "; 
    cout << endl; 

    return 0; 
} 

de cplusplus.com/reference et je reçois l'avertissement du compilateur:

iterator.cpp: In member function 'myiterator& myiterator::operator++(int)': 
iterator.cpp:13: warning: reference to local variable 'tmp' returned 

Quel est le problème ici? La signature de suffixe est-elle censée être myiterator operator++(int), c'est-à-dire retour en valeur?

Y a-t-il quelque part à quoi devrait ressembler la signature postfix sur les itérateurs STL?

+0

cplusplus.com est utile, mais ne fait pas autorité. Dans ce cas, cela vous a blessé. Si vous regardez le code STL réel, vous constaterez que l'itérateur est souvent retourné en valeur, ce que cplusplus.com ne vous a pas dit que vous pourriez faire. –

+0

http://stackoverflow.com/questions/3181211/prefix-postfix-increment-operators –

Répondre

5

Y a-t-il quelque part à quoi devrait ressembler la signature postfix sur les itérateurs STL?

La norme.

La norme dicte de telles choses. Dans le cas de cette opération, la norme dit essentiellement "vous devez retourner quelque chose qui est convertible en const X&" où X est l'itérateur. En pratique, cela signifie que vous pouvez retourner par référence si cela s'applique à vous (ce n'est pas le cas), ou retourner en valeur.

Voir 24.1.3/1

+0

Merci d'avoir lu la question correctement et d'être à l'un seul réellement répondre à ce que je cherchais. – chris

3

Vous ne voulez pas renvoyer la référence: en faisant cela, vous renvoyez une référence à une variable qui, au moment où la fonction est retournée, n'existe plus. Tout ce que vous avez besoin est:

myiterator operator++(int) {myiterator tmp(*this); operator++(); return tmp;} 
+0

+1 Voici la réponse. J'ajouterai seulement que le message d'erreur vous a dit exactement quel était le problème, et la solution logique à l'erreur donnée est en fait la bonne réponse. Renvoyez la chose par valeur, non par référence. –

+0

Je sais. C'est le code de cplusplus.com. Je suis vraiment à la recherche de la définition de l'opérateur d'incrément de postfix pour les itérateurs STL ... – chris

+0

J'ai raté le lien que j'ai lu la première fois. Oui - cplusplus.com est faux ici. Excepté peut-être un cas extrêmement bizarre, ce qui précède sera ce à quoi ressemble un opérateur de postfix. Il n'y a pas de règle disant qu'il ne peut pas renvoyer une référence - ce n'est généralement pas le cas parce que cela n'est pas approprié. – Thanatos

0

vous retournez une référence à une variable qui est détruit lors de la sortie de la méthode. le compilateur vous avertit des conséquences de cela. au moment où la référence est reçue par l'appelant, la variable qu'il référence n'existe plus.

2

Cette ligne:

myiterator& operator++(int) {myiterator tmp(*this); operator++(); return tmp;} 

devrait être:

myiterator operator++(int) {myiterator tmp(*this); operator++(); return tmp;} 
//  ^^^^ Not return by reference. 
//   Don't worry the cost is practically nothing for your class 
//   And will probably be optimized into copying the pointer back. 

Comme une note de côté:

Vous ne avez pas réellement besoin du constructeur de copie:

myiterator(const myiterator& mit) : p(mit.p) {} 

Le compilateur a généré des versi fonctionnera parfaitement (car la règle des trois/quatre ne s'applique pas car vous ne possédez pas le pointeur RAW contenu dans votre classe). Vos opérateurs de comparaison devraient probablement être marqués comme const et je préfère personnellement définir l'opérateur! = En termes de l'opérateur = == et laisser le compilateur optimiser toute inefficacité (bien que ce soit juste une chose personnelle).

bool operator==(const myiterator& rhs) const {return p==rhs.p;} 
bool operator!=(const myiterator& rhs) const {return !(*this == rhs);} 
          //  ^^^^^^^ Added const 

L'opérateur * devrait probablement avoir deux versions. Une version normale et une version const.

int&  operator*()  {return *p;} 
int const& operator*() const {return *p;} 

En dernière note: Un pointeur par lui-même est- un itérateur. Donc, vous n'avez pas besoin d'envelopper les pointeurs pour les rendre itératifs, ils se comporteront correctement comme des itérateurs (et pas seulement des itérateurs d'entrée, mais des itérateurs à accès aléatoire).

+0

+1 pour l'explication détaillée – chris