2010-12-10 81 views
1

Supposons que je souhaite lire les lignes de la console et les placer dans un conteneur jusqu'à ce que l'utilisateur entre une ligne vide. Cependant, je ne veux pas que cette ligne blanche se retrouve dans mon conteneur. Je peux penser à cinq solutions différentes:Lecture jusqu'à ce que l'utilisateur entre ligne vide

a) la rupture de la boucle

std::vector<std::string> container; 
for (; ;) 
{ 
    std::string line = get_input(); 
    if (line.empty()) break; 
    container.push_back(line); 
} 

b) lire avant boucle et à l'intérieur boucle

std::vector<std::string> container; 
std::string line = get_input(); 
while (!line.empty()) 
{ 
    container.push_back(line); 
    line = get_input(); 
} 

c) lu dans le cadre de l'état de la boucle, la version d'affectation

std::vector<std::string> container; 
std::string line; 
while (!(line = get_input()).empty()) 
{ 
    container.push_back(line); 
} 

d) lu dans le cadre de l'état de la boucle, la version de la séquence

std::vector<std::string> container; 
std::string line; 
while (line = get_input(), !line.empty()) 
{ 
    container.push_back(line); 
} 

e) lire trop, l'enlever après la boucle

std::vector<std::string> container; 
std::string line; 
do 
{ 
    line = get_input(); 
    container.push_back(line); 
} 
while (!line.empty()); 
container.pop_back(); 

Alors, quelle solution préférez-vous et pourquoi? Quel serait le plus facile à comprendre pour un débutant?

Répondre

2

Je préfère (a). simple et lit tout naturellement. (B) répète la ligne qui reçoit l'entrée. (C) et (d) utilisent tous deux une syntaxe pouvant être source de confusion pour les débutants (en particulier, la virgule ne se trouvant pas dans une instruction for ou une définition, et une affectation dans une condition). Je préférerais probablement (c) plus (d) cependant.

(e) est ... inefficace. Que faire si cette dernière push_back a causé une réallocation?

0

Comme vous vous attendez probablement de moi, je vous suggère un proxy:

class non_blank { 
    std::string data; 

    friend operator>>(std::istream &is, non_blank &n) { 
     std::string temp; 

     std::getline(is, temp); 

     // I'm not writing this from home, so I'm going from memory. 
     // The following line is probably a little wrong. 
     is.setbit(std::ios::fail, temp.length()!=0); 
     return is; 
    } 
    operator std::string() { return data; } 
}; 

non_blank line; 
while (infile >> line) 
    container.push_back(line); 

Cela a un effet secondaire qui pourrait être inattendu que: car il attend de lire les lignes non-vides, il considère une ligne vide comme une conversion échouée - ce qui signifie que pour lire plus à partir du flux après, vous devez effacer le bit d'échec du flux. Comme cela fonctionne en définissant le bit d'échec du flux, vous devriez également pouvoir utiliser std::copy pour lire l'entrée et il s'arrêtera à la conversion ayant échoué.

+0

qui est bien surpuissant essayant d'accomplir. –

+0

Je suppose que cela dépend de combien de fois vous avez besoin de le faire - si vous ne l'utilisez qu'une fois, je peux voir où vous pourriez argumenter que c'était en quelque sorte exagéré, mais étant donné que c'est seulement environ 10 lignes de code, je ne pensez pas que vous auriez à l'utiliser très souvent pour le justifier. –

2

j'utiliser la méthode « d » en fait:

montre -It à mon avis, mieux ce qui se fait: lisez d'abord les données, si ce ne sont pas des données « bonnes » (ligne vide) arrêter la lecture les données. Et tout est à la position attendue (vérifier les données est dans la partie de condition de boucle, manipulant les données dans le corps de boucle.)

Mtheod "a" cache la condition vérifiant & c'est plus difficile (à mon humble avis) pour ce qu'il est de voir la condition qui « arrête » la boucle.

0

Une modification (d) le rend plus efficace et suit ce que vous essayez de faire mieux.

std::vector<std::string> container; 
std::string line; 
do 
{ 
    line = get_input(); 
    if (!line.empty()) 
    { 
     container.push_back(line); 
    } 
    else 
    { 
     break; 
    } 
} 
while (true);