tresinformal / drakkar

The tresinformal video game called 'Drakkar'
GNU General Public License v3.0
11 stars 4 forks source link

C++ Core Guideline of September #586

Closed richelbilderbeek closed 1 year ago

richelbilderbeek commented 2 years ago

noexcept or polymorhism?

richelbilderbeek commented 2 years ago

It should not be possible to ignore an error because that could leave the system or a computation in an undefined (or unexpected) state. This is a major source of errors. Example

int printf(const char* ...);    // bad: return negative number if output fails

template<class F, class ...Args>
// good: throw system_error if unable to start the new thread
explicit thread(F&& f, Args&&... args);

Simpler examples:

// bad: return negative number if output fails
int say_hello(const std::string& name)
{
  if (name.size() == 0) return 1;
  std::cout << "Hello " << name << '\n';
}

// good: throw std::logic_error if string is invalid
void say_hello(const std::string& name)
{
  if (name.size() == 0) throw std::logic_error("A name has at least one character");
  std::cout << "Hello " << name << '\n';
}

// maybe superior: the class 'name' has already checked that the name is at least one character
void say_hello(const name& n) noexcept
{
  std::cout << "Hello " << name << '\n';
}

Example in our code:

// Current
void game::eat_food(food& f)
{
  if(f.is_eaten()) 
  {
    throw std::logic_error("You cannot eat food that already has been eaten!");
  }
  f.set_food_state(food_state::eaten);
  f.reset_timer();
}

// Alternative
void game::eat_food(food& f)
{
  assert(!f.is_eaten());
  f.set_food_state(food_state::eaten);
  f.reset_timer();
}

Q: When to use exceptions? A: When you want to test a function to fail:

// (123) say_hello detect an empty name
{
  bool has_thrown{false};
  try
  {
    say_hello("");
  }
  catch (const std::logic_error& e)
  {
    has_thrown = true;
  }
  assert(has_thrown);
}
richelbilderbeek commented 1 year ago

Done!