11

I want to add unique ID (within a single session) to each object of a certain class. One solution is to use a factory function which increments some static counter. A simpler solution is to add this counter to the class itself, e.g.:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};        
    long id;

private:
    static long next_id = 0;
}

A flaw, however, is that the id field is public, and can be changed by the caller, thus violating its uniqueness. A traditional (well, at least in my eyes) is to make id private, and use a getter function to access it, thus:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};                
    long getId() const { return id; };

private:
    long id;
    static long next_id = 0;
}

But I'm considering a different approach. I can make id a const public class field:

class fooWithUniqueId {
public:
    fooWithUniqueId() : id(next_id++) {...};                
    const long id;

private:
    static long next_id = 0;
}

I like this way better because I don't have to keep calling getId() each time I need the id, I can use the id as a key in a map (as copy construction correctly initializes the id of the copy object). One disadvantage I can think of is that I cannot implement assignments between fooWithUniqueId objects, although currently I do not need this feature.

  • What are the pros and cons of each approach (getter function / const field)?
  • Assuming I'm using the 'const' approach, is there any way to later implement an assignment operator without breaking the code?

Thanks, Boaz

bavaza
  • 10,319
  • 10
  • 64
  • 103
  • 1
    Are you sure you really want to copy the ID as well in the assignment operator? After all, your ID has to be unique. – Vlad Feb 13 '11 at 13:31
  • @Vlad: you are probably right, and currently I do not intend to implement an assignment operator. I'm asking because I do not want to have to refactor a lot of code should the need arises. – bavaza Feb 13 '11 at 14:27

2 Answers2

6

I can use the id as a key in a map (as copy construction correctly initializes the id of the copy object)

What do you mean by "correctly"? The default copy constructor will copy the ID, whether it is stored in a private or a public member variable, and you will end up with two objects sharing the same ID. This might not be what you want.

In general, you should never use public variables in C++ as it violates proper encapsulation. Always use a (inline) getter method. The only disadvantage is that you have to type a few more characters.

I strongly suggest that you stick to best practices and use a private field with a getter function.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • 15
    How does a scoped constant break encapsulation? – Šimon Tóth Feb 13 '11 at 14:16
  • 3
    @Ferdinand: no offence meant, but I think that NEVER using public fields is rather strict, especially since I intend to use that specific class as POD, and it may have many, many fields. Do you really recommend writing a getter/setter for each and every one of them? – bavaza Feb 13 '11 at 14:28
  • It's better to use a struct to keep all your fields grouped and have a setter/getter to the struct field. And don't use inline. Compiler must determine itself to make the function inline or not in 99% of situations. http://www.parashift.com/c++-faq-lite/inline-functions.html – Andrew Feb 13 '11 at 14:36
  • 1
    @Let_Me_Be: I wrote "variable", not "constant". – Ferdinand Beyer Feb 13 '11 at 17:54
  • @bavaza: With programming guidelines, you are always (well, most of the times) allowed to break the rules if you know what you are doing. I wrote "never" to emphasize that in 99% of the time, you should avoid public variables. – Ferdinand Beyer Feb 13 '11 at 17:56
  • @Andrew: Did you read the link you posted? It is not helpful to advice not to use inlines at all. In fact, if you don't use `inline`, the compiler has no chance to make the function inline since it won't see its implementation. Simple getter and setter functions are the prime examples of when you *should* use inline functions! – Ferdinand Beyer Feb 13 '11 at 17:59
  • @Ferdinand: I've read the link. Good compilers have an auto-inline function that lets the compiler decide which functions to inline and which to leave as is. I think you should not usually use inline functions in your code (for many reasons http://accu.org/index.php/journals/449 ) because it's a compiler's prerogative. If you program work slow with no inlining then you have to find the bottle neck an maybe inline functions there. – Andrew Feb 13 '11 at 18:29
  • @Andrew: Of course declaring an inline function is just a hint to the compiler to decide whether to inline it or not. But without this hint, a typical compiler will **never** inline it. Sure, you might consider inlining as a case of "premature optimization". On the other hand, there is no reason **not** to inline simple getter functions. – Ferdinand Beyer Feb 13 '11 at 18:44
6

It is quite ok to have a public member constant in a class, if the design shows that it should never change. A unique id seems like such a case.

The fact that the const member disables assignment seems like an advantage to me. If you assign one instance to another, the ids will not be unique anymore!

Bo Persson
  • 90,663
  • 31
  • 146
  • 203