Question

I want to define a new type in C++ which is just some primitive type (in my example an int, could be any type). I call the type NodeId in this example.

I could just use typedef int NodeId. I want a default value for NodeIds, so I would use #define NULL_NODE_ID -1.

Now, I think it would be nicer to define a class instead of typedef to allow a function isValid() and a default constructor constructing a null NodeId:

class NodeId
{
    int value;
public:
    inline NodeId() : value(-1) {}
    inline NodeId(int value) : value(value) {}
    inline operator int() {return value;}
    inline bool isValid() {return value != -1;}
    //...
};

Are there any performance disadvantages which result in using the second method?

Was it helpful?

Solution

Actually, there are two reasons this could conceivably be slower.

First, there's no way to create an uninitialized NodeId. Normally, that's a good thing. But imagine you have code like this:

NodeId nodeid;
foo.initializeNodeId(&nodeid);

You'll be doing an extra assignment which isn't actually necessary.

You can fix that by adding a special constructor. It's probably much better to create a Foo::createNodeId() so you don't need Foo::initializeNodeId(&NodeId), but if you don't control the definition of Foo, that may not be possible.

Second, a NodeId is not a compile-time constant expression. As dasblinkenlight suggests, this is far more likely to cause problems with code not being legal than to cause performance problems, but both are possible. (Why? Because you may be forcing the compiler to insert code to do some calculation at runtime that could have been done at compile time, if you were using an int. Not that this is likely to be an issue for a class called NodeId…)

Fortunately, if you're using C++11, you can fix that with constexpr. And if you want your code to also be legal C++03, you can deal with that with a macro.

Also, as pointed out by dasblinkenlight, you're missing const in two methods.

Finally, there's no reason to write "inline" on methods that are defined inside the class definition; they're already inherently inline.

Putting it all together:

#if __cplusplus > 201000L
#define CONSTEXPR_ constexpr
#else
#define CONSTEXPR_
#endif

class NodeId
{
    int value;
public:
    struct Uninitialized {};
    CONSTEXPR_ NodeId() : value(-1) {}
    CONSTEXPR_ NodeId(Uninitialized) {}      
    CONSTEXPR_ NodeId(int value) : value(value) {}
    CONSTEXPR_ operator int() const {return value;}
    CONSTEXPR_ bool isValid() const {return value != -1;}
    //...
};

Now you can do this, to avoid the cost of an extra -1 assignment.

NodeId nodeId(NodeId::Uninitialized());
foo.initializeNodeId(&nodeid);

And this, to legally use a NodeId as a non-type template parameter:

myClassTemplate<NodeId(3)> c;

Or, this, to be sure the compiler can legally just initialize x to 4:

int x = 3;
x += NodeId(1);

OTHER TIPS

If you use a relatively new compiler, then the generated code should be the same. The compiler should have no problem inlining those member functions. In case you really have doubts about it, you can always disassemble the executable.

If the compiler optimization settings let the compiler inline everything, there should be no performance differences. The only disadvantage that I can spot is that expressions based on objects of this class may no longer qualify as compile-time constants, which may be important in template programming. Other than that, you end up with additional clarity at no runtime cost.


P.S. You are missing const in your operator int and isValid:

inline operator int() const {return value;}
inline bool isValid() const {return value != -1;}

If you are planning on making this into a library that may get used by some other programming language (like if you are writing this into a C++ DLL) there are definite advantages to having it a typedef int.

For example, when you are writing a python wrapper or a java wrapper for your API, you don't have as much headache getting your class and types to port over. Then all you have to worry about is the bit size of the int.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top