16

I'm trying to create a Data class whose objects each hold a unique ID.

I want the 1st object's ID to be 1, the 2nd to be 2, etc. I must use a static int, but all the objects have the same ID, not 1, 2, 3...

This is the Data class:

class Data
{
private:
   static int ID;
public:
   Data(){
   ID++;
   }
};

How can I do it so the first one ID would be 1, the second would be 2, etc..?

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
Jjang
  • 243
  • 1
  • 6
  • 13
  • Make sure that you take care of multithreading, as the variable is `static`. – iammilind Jun 04 '12 at 12:43
  • Generally people use `long` for this rather than `int`. – shan Jun 04 '12 at 12:43
  • 1
    @shan: Which people? It can be whatever he wants. –  Jun 04 '12 at 12:44
  • @0A0D `long` is wider than `int`. If we don't know how many objects we want, better to use `long`. – shan Jun 04 '12 at 12:47
  • @shan: It will rollover back to negative (or zero if it is unsigned). `long` will rollover eventually too. Unsigned int goes to 65535. It all depends on the application. –  Jun 04 '12 at 12:50
  • @shan: It depends on the architecture and compiler. In many architectures `long` is exactly the same size as `int`. On the other hand, it *should* really be `unsigned` (of whatever length). @0A0D: `unsigned int` goes to 65535?? what architecture are you on that still has 16bit `int`? – David Rodríguez - dribeas Jun 04 '12 at 13:16
  • I do not understand what you mean by "*... but all the objects have the same ID, not 1, 2, 3..*" – Happy Green Kid Naps Jun 04 '12 at 13:29
  • @DavidRodríguez-dribeas: Oops, meant unsigned short. –  Jun 04 '12 at 13:59
  • @DavidRodríguez-dribeas: The standard answer to 'what architecture are you on that still has 16bit int?' - an embedded system of some kind. They do exist. – tinman Jun 04 '12 at 15:09

5 Answers5

23

This:

class Data
{
private:
   static int ID;
   const int currentID;
public:
   Data() : currentID(ID++){
   }
};

Besides a static counter, you also need an instance-bound member.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    The member id should be a `const` field. Once the object is created it probably makes little to no sense to change it. It will also automatically inhibit `operator=` from overwriting the id of the object, even though the user is left with the responsibility of providing a copy constructor that does not reuse the source object's id. – David Rodríguez - dribeas Jun 04 '12 at 14:13
  • I hit some error using `const` perhaps due to my user-declared copy constructor. See [this answer](http://stackoverflow.com/a/37517125/5272567). Removing `const` "fixed" this, of course that means the variable isn't `const`. – Matthias Apr 18 '17 at 14:48
  • What value is `ID` initialized to here, and how? – dekuShrub Mar 05 '19 at 20:16
  • 1
    @dekuShrub the initialization is left out, there's an example in Brady's answer. – Luchian Grigore Mar 05 '19 at 22:24
  • I thought it might be the case, but wasn't sure since my linter didn't complain when I tried without it, thanks! ^^ – dekuShrub Mar 06 '19 at 09:12
16

If the ID is static, then it will have the same value for all class instances.

If you want each instance to have sequential id values, then you could combine the static attribute with a class variable, like this:

class Data
{
private:
   static int ID;
   int thisId;
public:
   Data(){
   thisId = ++ID;
   }
};

int Data::ID = 0;

If the application will be multi threaded, then you'll have to synchronize it with something like a pthread mutex.

Brady
  • 10,207
  • 2
  • 20
  • 59
  • thanks, thought about this solution but I was wondering if there is another way to do it, only with the static int, since I was requested to do it using static int only. thanks! :) – Jjang Jun 04 '12 at 12:47
  • @Jjang, you could do it with just one static int if you just print the value in the constructor, but if you need to ***store*** the unique sequential value, then you'll need more than just the static int. – Brady Jun 04 '12 at 12:49
  • 1
    @Jjang: You cannot have *unique* id's per object with a single *shared* id (`static`), that makes no sense at all. – David Rodríguez - dribeas Jun 04 '12 at 14:14
4

Initialization of static variable within a function is allowed so a solution can be something like this

 class Data
 {
    private:
    static int ID ()
    {
       static int ID = 0;
       return ID ++;
    }
    int myId;

    public:
    Data(): myId (ID ())
    {      
    }
 };
elxala
  • 291
  • 3
  • 5
1

Each instance of Data needs its own non-static member variable that stores its ID. A static variable can be used to store the last used ID which would be incremented in the constructor of Data.

Instead of a static counter, which is not thread-safe, consider using boost's uuid:

#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

using boost::lexical_cast;
using boost::uuids::uuid;
using boost::uuids::random_generator;

std::string id_ = lexical_cast<std::string>((random_generator())());
hmjd
  • 120,187
  • 20
  • 207
  • 252
0

where is the instance(non static) id here? you need to declare a new instance ID field like this

int m_ID;

then in your constructor do

Data(){m_ID = ::InterlockedIncrement(&ID);}

in an interlocked or other thread-safe way

Ventsyslav Raikov
  • 6,882
  • 1
  • 25
  • 28