My input system has a GetKey() method that returns a key in a map. Simple enough.
However, I want to know if the key is not available - be it a typo, or misuse of wording, or something else.
I am the only person working on this project; would it be a good idea to simply set some compile time throw to see if it catches one? Is this even possible?
What I'm meaning is:
if(entry is not found) { throw something("couldn't find key"); exit(); }
Rather than an approach of
if(entry is not found) { try and compensate somehow and continue } And then go through the code and find where I've made a mistake. Of course, for a large project I would want real error handling like the second. But I can just get rid of these errors, since there's no modding. But I'm the only one working, so is this probably the easiest way to do it?
Well, it's this or make some kind of BLANK key and check it every query.
EDIT: I am using strings as my keys, so no translate functions would be easy.
Double EDIT: I bind commands (strings) to keys (wrapper over an enum value). It means it's more understandable to check if "move_left" has been pressed than if keyCode::A has been, as well as being more changeable.


closed as primarily opinion-based by Josh Nov 11 '14 at 17:11

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\begingroup\$ Can't you just set a breakpoint inside if(entry not found) { } and handle it like method 2? That way the debugger will stop at the line when an invalid key is pressed and even provide you with information about all the function calls that led up to it. \$\endgroup\$ – 5ound Aug 2 '10 at 19:12

When debugging, it's great to throw an exception. When the user has the program and encounters something that you missed, it's not; you might want to silently log the error, or ignore the call and just return from the function, but you probably don't want to throw an exception and stop everything just because there's a bug in your code unless it's a showstopper.

C and C++ support assertions via assert.h; I like to use those, and this would be a good place for one. For example, at the top of the GetKey method, do an assert that the key is found.

However this is also a good place for using an enum rather than a char or whatever you're currently using. That way, the programmer must use a value from the enum and there's not really a possible way to feed it anything else.

  • 1
    \$\begingroup\$ I agree. I find it good to limit the number of states a variable can have to the ones actually used in logic. This really helps in debugging and testing. Enumerations are great for this if supported in your specific language. \$\endgroup\$ – Staffan E Aug 3 '10 at 7:29
  • \$\begingroup\$ +1 - exception: ok; assert: better; using a language construct that actually maps to the problem domain: best ;) \$\endgroup\$ – Andrew Russell Aug 3 '10 at 14:33
  • \$\begingroup\$ @Andrew: Exactly, that's the message I was going for! :) \$\endgroup\$ – Ricket Aug 3 '10 at 15:29

You can't do anything like look up a string key from a hash table at compile time, because that would involve executing code.

However you CAN use something like static_assert (Visual Studio or Boost)to do things like check for enum values. static_assert lets you check any const expression, and can be very useful for setting up certain safeguards. For instance if you had two enum structures that are independent but should be related to each other, you can static_assert that the two enum values are the same. You can also static assert on sizeof, offsetof, and other compile-time functions.

  • \$\begingroup\$ So theoretically you can do <br> #define keycode(key) \<br> #if (key == "KeyCode::a") || \ <br> (key == "KeyCode::b") || \ <br> ..etc..\<br> key #else \<br> static_assert (or anything that generates a compile error for that matter) \<br> #endif<br> <br> Although it's not something I'd like :o\ it would allow all keys that are defined in the 'if' and fail on everything else. Unfortunately, the compilation error would show in the define and not in the calling code. ...edited to add - errr, <br> was supposed to be newline. Guess you can't in a comment :o\ \$\endgroup\$ – Kaj Aug 2 '10 at 21:55
  • 1
    \$\begingroup\$ You can't do that from #if, because #if is a preprocessor-time instead of a compile-time directive. The preprocessor doesn't know anything about the value of key. The use of == on strings is also problematic. I haven't tried it myself but I suspect it will fail to compile because it involves checking pointer addresses of strings \$\endgroup\$ – Ben Zeigler Aug 3 '10 at 0:44
  • \$\begingroup\$ Wow, caught out for sure - it's one of those things that seemed in my mind it would work but sure enough it won't. If I could downvote myself I would. Upvoted you instead. \$\endgroup\$ – Kaj Aug 3 '10 at 1:30

Why not make a translate function that always gets called? That way you'll only have to look in one place. If you, instead of actual keycodes, use an enum the compiler will complain by default when you enter an invalid code) - the translate function can convert that enum to its actual keycode and is in charge of what input is valid.

Edited to add: abstracting the input out to one location will also make it a lot easier to make your keyboard layout redefinable.

  • \$\begingroup\$ I'm using strings, I should've made it clearer, my apologies. \$\endgroup\$ – The Communist Duck Aug 2 '10 at 17:35
  • \$\begingroup\$ Any specific reason for that? I don't think you could trip a compile time error on that, except with fairly heavy constructs. An ASSERT would give you run-time information, but it's barely safe - what if you have code that only gets run when the player does something very specific and only on xmas eve? If you forgot to test it, but had typed an invalid key your game would ship with unsafe code. Using a define (or constants) would prevent this. I don't quite see from your edit why you need strings. In the UI, sure, but in code "KeyCode::A" can be mapped to enum keycode_A, just like move_left? \$\endgroup\$ – Kaj Aug 2 '10 at 20:36

While it's more elegant to transform the problem so that you can utilize the static checking mechanisms of your language or existing tools (e.g. enum + lint or higher warning setting), you can roll your own tool if you're not able to do this.

  • If you have a centralized list of valid key values, and
  • you always use a reasonably consistent syntax where you're using them (e.g. getKey("foo")), and
  • you're not using more complicated logic to build key strings before use (e.g. keyString = "move_" + directionString; bar = getKey(keyString);)...

...then you might be able to use a simple grep-like mechanism in <insert-your-scripting-language-of-choice> to make a list and scan your source files.

It's possible to get some false positives and false negatives here. Too many, and maintaining the tool starts to become more of an effort than it is worth.

We have used a tool like this for a localization system, checking that all of our "string ids" actually match up to real strings. These string ids are used in c, cpp, and lua sources, and also in json, xml, and other "baked" forms of data. It's not perfect; it gives up when the string id was piecewise constructed by earlier code rather than being a literal.

One other nifty thing you can do with this is turn more expensive string literals into less expensive unique IDs or hashes as a pre-precompile step. If you don't control your build process this can get to be a pain, and if the tool is slow at all you get slow builds (which I loathe with the burning passion of a thousand fiery suns -- but that's another answer)... but you may already be doing some pre-preprocessing for e.g. swig or similar tools. This has the advantage of mandating a consistent syntax, and it'll fail your build if there's anything wrong.

(There are definitely tools out there that do this latter thing; look around a bit!)


Not the answer you're looking for? Browse other questions tagged or ask your own question.