-4

I'm using a do..while loop to allow my program to exit if a condition is correct, but I've seen in examples when I was in school where an exception was thrown in order to quit. Those examples used a regular infinite for loop. I'm thinking that I could use an if statement to break from the for loop rather than throwing, but I'm not sure. Code below:

// main.cpp

#include <cstdlib>
#include <iostream>
#include <string>

#include "commands.h"

using namespace std;

int main(int argc, char *argv[]) {
    bool exit = false;

    try {
        do {
            try {
                // Read a line, break at EOF, and echo print the prompt
                // if one is needed.
                string line;
                getline(cin, line);
                if (cin.eof()) {
                    cout << endl;
                    break;
                }

                command_fn fn = find_command_fn(line);
                fn();
            }
            catch (command_error& error) {
                // If there is a problem discovered in any function, an
                // exn is thrown and printed here.
                cout << error.what() << endl;
            }
        } while (!exit);
    }
    catch (exception& e) {

    }

    return 0;
}

// commands.h

#ifndef __COMMANDS_H__
#define __COMMANDS_H__

#include <unordered_map>
using namespace std;


// A couple of convenient usings to avoid verbosity.

using command_fn = void (*)();
using command_hash = unordered_map<string,command_fn>;

// command_error -
//    Extend runtime_error for throwing exceptions related to this 
//    program.

class command_error: public runtime_error {
   public: 
      explicit command_error (const string& what);
};

// execution functions -

void fn_connect     ();
void fn_disconnect  ();
void fn_test        ();
void fn_exit        ();

command_fn find_command_fn (const string& command);


#endif

// commands.cpp


#include "commands.h"

command_hash cmd_hash {
   {"c"  , fn_connect   },
   {"d"  , fn_disconnect},
   {"t"  , fn_test      },
   {"e"  , fn_exit      },
};

command_fn find_command_fn (const string& cmd) {
   // Note: value_type is pair<const key_type, mapped_type>
   // So: iterator->first is key_type (string)
   // So: iterator->second is mapped_type (command_fn)
   const auto result = cmd_hash.find (cmd);
   if (result == cmd_hash.end()) {
      throw command_error (cmd + ": no such function");
   }
   return result->second;
}

command_error::command_error (const string& what):
            runtime_error (what) {
}

void fn_connect (){
}

void fn_disconnect (){
}

void fn_test (){
}

void fn_exit (){

}

Edit: Have included more source. I have lots of blanks because I'm rewriting a program that sends data via UDP. I'm just looking for some recommendations as to how to quit the program safely.

ConductedForce
  • 194
  • 2
  • 14
  • 1
    There is no exception thrown in the code. – 273K Jul 19 '19 at 22:40
  • 1
    What is `command_error`? And why do you think that code might throw it? –  Jul 19 '19 at 22:40
  • 5
    Exceptions should only be used for exceptional behaviour. If the loop is intended to be forever unless something rare and dramatic (an open and happy serial port vanishes, for example) happens the exception is probably the right choice. If the user hit the wrong key, that's not exceptional. Users screw up all the time. That should be handled with standard error handling. – user4581301 Jul 19 '19 at 22:41
  • 2
    @user4581301 A problem is that some languages (like Java) throw exceptions for anything invalid. Then persons who are used to those languages bring that type of programming to C++, thinking it's a good idea to write code in that manner. – PaulMcKenzie Jul 19 '19 at 22:53
  • I was trained in Java before moving to C++. That might be the start of my confusion. – ConductedForce Jul 19 '19 at 22:59
  • I lived that one, @PaulMcKenzie . After ten years of C, five years of Java, a couple university courses on C++ and three years of writing something C++-ish I thought I knew C++. LOL. Then I got me some books and rewrote three years of code. – user4581301 Jul 19 '19 at 23:00
  • I added more source so the program makes more sense. I'm still having a form issue. This particular implementation might be overly complex to do function mapping. I'm not certain, but I get that vibe when looking at how to add in a try catch for socket exceptions. – ConductedForce Jul 19 '19 at 23:20
  • Unrelated: Something else they don't teach in school is there are some fairly specific (and ing lethal when they bite) [rules about when and where you can use an underscore](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). In this case you've tripped over *Never use two underscores in a row*, making `#ifndef __COMMANDS_H__` illegal without the compiler having to issue a diagnostic to warn you that you could be in for a world of hurt.. – user4581301 Jul 19 '19 at 23:33
  • After the question updated, still no std::exception thrown and there is no loop terminated by an exception. – 273K Jul 19 '19 at 23:40
  • 2
    Going through what you have posted you can avoid the exception by returning a `std::pair` or a [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional) if building for C++17 or newer. – user4581301 Jul 19 '19 at 23:53
  • Or, now that I think of it, just return `bool` and call the function directly in `find_command_fn` if it's found. If you go this route, you'll want to change the functions's name to match the new responsibility. – user4581301 Jul 19 '19 at 23:56
  • That sounds pretty good, I'll try that. – ConductedForce Jul 19 '19 at 23:58

1 Answers1

0

do...while is completely equivalent to a for loop except the test is done at the end of the loop instead of at the beginning, so a do...while always runs at least once. In both cases you can exit the loop with break. You don't need to throw an exception, but of course you can. If you're multiple levels deep, it's often easier to throw an exception and either catch it in the loop and break, or set the termination condition, or else catch the exception outside the loop which will also terminate it.

GaryO
  • 5,873
  • 1
  • 36
  • 61
  • 1
    Sidenote: When I have multiple loops and I need to get out in the middle, I put the loops in their own function and `return` from the function. It's cheaper than an exception and often helps readability because once you get more than a couple indents deep, your function's probably trying to do too much. – user4581301 Jul 19 '19 at 23:37