2014-11-21 2 views
-1

Мне интересно сделать «CMD» -подобный. Я имею в виду, что пользователи могут вводить свои команды в консоли. Проблема у меня в том, что все команды работают, но, например, если мы не пишем каждый args, прог-крах. Вот маленький кусочек кода:C++ Ловля расколотых человеческих ошибок

void commande(std::string commandeWanted) 
{ 
    std::vector<std::string> fields; 
    boost::split(fields, commandeWanted, boost::is_any_of("|")); // I chose | as spliter 
    boost::to_upper(fields[0]); 
    //std::cout<< fields[1] << fields[2] <<std::endl; 
    if (fields[0] == "STOP") 
     stop(fields[1]); 
    else if (fields[0] == "DISCONNECT") 
     disconnect(); 
    else if (fields[0] == "CONNECT") 
     connect(); 
    else if (fields[0] == "SEND") 
     send(fields[1], fields[2]); 
    else if (fields[0] == "clean") 
     cleanConsole(); 
    else if (fields[0] == "HELP") 
     displayHelp(); 
    else 
     std::cout << "No command recognized." << std::endl; 
} 

Любая идея? Любое предложение ? Я попытался объявить поля [1] и поля [2], но никак. Проблема в том, что я могу ввести «help», это запустит функцию displayHelp, но, к примеру, если я напишу «send» вместо «send | who | what», это приведет к сбою программы. Спасибо вам заранее.

+0

'станд :: string' в списке аргументов функции делает копию строка при вызове функции, которая довольно тяжелая и обычно не нужна. Возьмите 'const std :: string &' вместо этого, или, если вы хотите изменить строку, 'std :: string &'. – GingerPlusPlus

+0

Ну, ладно. Я использовал решение Джонатана Ми, и это сработало. Спасибо всем за вашу помощь, и у меня хороший день. Для полей переключения и чемпиона, это потому, что я французский, и я написал программу на французском языке. Но для должности я перевел его. – NorthernLight

ответ

0

Вам необходимо добавить проверки в свой код, чтобы до их доступа существовало достаточное количество полей.

(Также это выглядит, как вы перешли fields и champs в вашем split вызова.)

Что-то вроде этого:

void commande(std::string commandeWanted) 
{ 
    std::vector<std::string> fields; 
    boost::split(fields, commandeWanted, boost::is_any_of("|")); // I chose | as spliter 
    boost::to_upper(fields[0]); 
    //std::cout<< fields[1] << fields[2] <<std::endl; 
    if (fields[0] == "STOP"){ 
     if(fields.size >=2)stop(fields[1]); 
    } 
    else if (fields[0] == "DISCONNECT") 
     disconnect(); 
    else if (fields[0] == "CONNECT") 
     connect(); 
    else if (fields[0] == "SEND"){ 
     if(fields.size() >= 3)(fields[1], fields[2]); 
    } 
    else if (fields[0] == "clean") 
     cleanConsole(); 
    else if (fields[0] == "HELP") 
     displayHelp(); 
    else 
     std::cout << "No command recognized." << std::endl; 
} 
2

Проверить fields.size() >= 2 перед тем, как получить доступ к fields[1] и пр. Для fields[2].

1

Если вы нормализуете, что все ваши функции выглядеть, вы можете избежать много логического дублирования и размера агда проверки:

struct Command { 
    size_t numArgs; 
    std::function<void(std::vector<std::string>)> fun; 
}; 

std::map<std::string, Command> commands = { 
    {"STOP", {1, stop}}, 
    {"DISCONNECT", {0, disconnect}}, 
    {"SEND", {2, send}}, 
    // ... 
}; 

// after you split 
boost::to_upper(fields[0]); 

auto it = commands.find(fields[0]); 
if (it != commands.end()) { 
    // pop the first one 
    fields.erase(fields.begin()); 

    // check the size 
    if (fields.size() != it->second.numArgs) { 
     // error: wrong number of args 
    } 
    else { 
     // ok, call me 
     it->second.fun(fields); 
    } 
} 
else { 
    // command not found 
} 

К сожалению, C++ не имеет хороший эквивалента для оператора питона * распаковать вектор - но таким образом, по крайней мере, вы знаете, что у вас есть все правильные аргументы во всех правильных местах, даже если все ваши функции теперь берут вектор.

Смежные вопросы