4

I'm in the middle of refactoring a project (in C++11) and I'm struggling with a decision is it good to change huge enum with about 100 record to separate classes. This enum is used in about 4 places in code in 4 different functions with huge switch statements. For every enum, the record is some code in every function.

I'm thinking about creating an interface and them implement in classes but the number of classes in the project will increase by 100. That's why I'm concerned if this will cost me some performance decrease or will have a huge impact on memory usage or will have other consequences. I know that code will be in better condition but also it's very important that it will work fast (not extremely fast) but it's server application so it's an important factor.

Some code samples:

enum MyEnum {
  RECORD_1,
  RECORD_2,
  ...
  RECORD_100
}

void doSomething(MyEnum en) {
  switch (en) {
  case RECORD_1: {

  } break;
  case RECORD_2: {

  } break;
  //...
  case RECORD_100: {

  } break;
  };
}

void doSomethingElse(MyEnum en) {
  switch (en) {
  case RECORD_1: {

  } break;
  case RECORD_2: {

  } break;
  //...
  case RECORD_100: {

  } break;
  };
}

So I'm thinking in creating interface:

class AbstractInterface {
public:
  virtual void doSomething() = 0;
  virtual void doSomethingElse() = 0;
};

And then implemets this interface in classes:

class Record1 : public AbstractInterface {
public:
  void doSomething() override;
  void doSomethingElse() override;
};

//...

class Record2 : public AbstractInterface {
public:
  void doSomething() override;
  void doSomethingElse() override;
};

Is it a good way of refactoring this type of code in that way? and not decreasing the performance of the application?

Li Chen
  • 123
Piter _OS
  • 101
  • 1
  • 1
  • 6

2 Answers2

8

There is not going to be a huge change in performance. Your current solution uses a large switch/case for dispatch, your proposed solution uses dynamic dispatch. Both imply some indirection and/or branching. Both are essentially the same code.

There are a couple of tiny differences that would point to the switch being slightly faster:

  • Enums are typically backed by ints, but your objects will probably be a pointer to the object + one vtable pointer inside the object. So per instance you might have a 4× higher memory use, plus additional pointer indirection. Is this relevant? Likely not, unless you are storing many millions of instances at once.

  • The code for the different branches in the switch are right next to each other, which might be good for caching. In contrast, the objects, vtables, and method bodies for your objects might be all over the place. When calling a rarely-used method, the processor will have to wait until the data is loaded into the cache. OTOH the switch might be so large that it's never fully loaded into the cache either, so the same drawbacks may apply there.

There certainly are scenarios where cache-friendly programming makes a huge difference. For the majority of code, that's not the case. I'd like to point out that many languages such as Java or Python have fundamental inefficiencies in their object model, yet still deliver acceptable performance in many applications.

amon
  • 135,795
2

I'm thinking about creating an interface and them implement in classes but the number of classes in project will increase by 100.

Don't worry about it.

Even a basic, "Hello World", program probably uses [at least] that many classes from the .Net Framework.

Your 100 classes each of which "does its own thing" is going to be far more maintainable in the long term than your current, four methods that have to "know all about 100 different classes".

Phill W.
  • 13,093