Вы спрашиваете о чем-то «более эффективном», но, похоже, у вас нет конкретной цели производительности. То, что вы хотите здесь, вероятно, больше похоже на Code Review. Для этого есть сайт, в частности:
https://codereview.stackexchange.com/
Но все равно ...
Вы правы, интуитивно понимая, что четыре логических значения здесь на самом деле не нужны. Это 2 ^ 4 = 16 различных «состояний», во многие из которых вы никогда не попадете. (Ваша спецификация явно запрещает, например, keyword3_defined == true
, когда after_keyword1 == false
).
Состояние программы может храниться в перечислениях и логических значениях. Это позволяет «забытому» циклу пересмотреть строку кода при различных обстоятельствах, но при этом помнить, на какой стадии обработки он находится. Это полезно во многих случаях, в том числе в сложных синтаксических анализаторах. Но если ваша задача линейна и проста, лучше неявно «знать» состояние, основываясь на достижении определенной строки кода.
В качестве учебного примера, демонстрирующего контраст, о котором я говорю, приведу глупый конечный автомат для чтения букв A
, за которыми следует любое количество букв B
s:
enum State {
beforeReadingAnA,
haveReadAnA,
readingSomeBs,
doneReadingSomeBs
};
State s = beforeReadingAnA;
char c;
while(true) {
switch (s) {
case beforeReadingAnA:
cin >> c;
if (cin.good() && c == 'A') {
// good! accept and state transition to start reading Bs...
s = haveReadAnA;
} else {
// ERROR: expected an A
return EXIT_CODE_FAILURE;
};
break;
case haveReadAnA:
// We've read an A, so state transition into reading Bs
s = readingSomeBs;
break;
case readingSomeBs:
cin >> c;
if (cin.good() && c == 'B') {
// good! stay in the readingSomeBs state
} else if (cin.eof()) {
// reached the end of the input after 0 or more Bs
s = doneReadingSomeBs;
} else {
// ERROR: expected a B or the EOF
return EXIT_CODE_FAILURE;
}
break;
case doneReadingSomeBs:
// all done!
return EXIT_CODE_SUCCESS;
}
}
Как уже упоминалось, это стиль кодирования, который может быть очень и очень полезным. Но для этого случая это смешно. Сравните с простым линейным фрагментом кода, который делает то же самое:
// beforeReadingAnA is IMPLICIT
char c;
cin >> c;
if (cin.fail() || c != 'A')
return EXIT_CODE_FAILURE;
// haveReadAnA is IMPLICIT
do {
// readingSomeBs is IMPLICIT
cin >> c;
if (cin.eof())
return EXIT_CODE_SUCCESS;
if (cin.fail() || c != 'B')
return EXIT_CODE_FAILURE;
}
// doneReadingSomeBs is IMPLICIT
Все переменные состояния исчезают. Они не нужны, потому что программа просто «знает, где она». Если вы переосмыслите свой пример, то, вероятно, можете сделать то же самое Вам не понадобятся четыре логических значения, потому что вы можете навести курсор на строку кода и с уверенностью сказать, что эти четыре логических значения должны быть , если эта строка кода работает.
Что касается эффективности, то классы <iostream>
могут сделать жизнь проще, чем у вас здесь, и быть более идиоматически C ++, не вызывая C-измы, такие как atof
или когда-либо использовать c_str()
. Давайте посмотрим на упрощенную выдержку из вашего кода, которая просто читает двойные числа, связанные с «keyword1».
string line;
getline(cin, line);
istringstream split(line);
vector<string> tokens;
char split_char = ' ';
string each;
while (getline(split, each, split_char)) {
tokens.push_back(each);
}
double keyword1_first, keyword1_second;
if (tokens.size() > 2) {
if (tokens[0] != "keyword1") {
return EXIT_FAILURE; // input format error
} else {
keyword1_first = atof(tokens[1].c_str());
keyword1_second = atof(tokens[2].c_str());
}
}
Сравните это с этим:
string keyword;
cin >> keyword;
if (keyword != "keyword1") {
return EXIT_FAILURE;
}
double keyword1_first, keyword1_second;
cin >> keyword1_first >> keyword1_second;
Magic. Iostreams может определить тип, который вы пытаетесь прочитать или написать. Если он сталкивается с проблемой интерпретации ввода так, как вы просите, то он оставит ввод в буфере, чтобы вы могли попробовать прочитать его другим способом. (В случае запроса строки, поведение состоит в том, чтобы прочитать серию символов до пробела ... если бы вы на самом деле хотели целую строку, вы бы использовали getline
, как вы это сделали.)
Однако с обработкой ошибок вам придется иметь дело. Можно сказать iostreams использовать методологию обработки исключений, чтобы стандартным ответом на возникновение проблемы (например, случайным словом в месте, где ожидалось двойное число) было аварийное завершение вашей программы. Но по умолчанию устанавливается флаг сбоя, который необходимо проверить:
ошибочное поведение
В iostream есть нюанс, так что вы, вероятно, захотите провести некоторый обзор вопросов и ответов ... Я немного учился в последнее время, отвечая / спрашивая здесь:
Ошибка вывода, когда ввод не является числом. C ++
Когда использовать printf / scanf против cout / cin?