Pella86
Pella86

Reputation: 500

Destructor Constructor calls

I'm a beginner programmer, and I was wondering...

I need a unique ID for my object in a game

so I thought I define a global class that holds the global id, and when I call the constructor of an object it will be incremented, while calling the destructor of that object it decrements it.

Is it true that for every constructor call there will be a corresponding destructor?

class id_holder{
private:
    int id_count;

public:
    id_holder() {id_count = 0 ; std::cout<< "unique_id: I'm constructed"<<std::endl;}

    ~id_holder(){std::cout<<"unique_id: I'm destructed"<<std::endl;}

    void increment_id(){id_count ++;};
    void decrement_id(){id_count --;};

    int get_id() {return id_count;};

};

class BaseObject {
protected:
    void increment_id();
    void decrement_id();
public:
    virtual ~BaseObject(){decrement_id();}
    BaseObject();
    BaseObject(V2 pos, ObjectType idobj, double s, Color col);
};

BaseObject::BaseObject(){   
    //stuff
    increment_id();
    unique_id = bObj_id_counter.get_id();
}


BaseObject::BaseObject(V2 pos, ObjectType idobj, double s, Color col){
    //stuff
    increment_id();
    unique_id = bObj_id_counter.get_id(); 
}

void BaseObject::increment_id(){
    bObj_id_counter.increment_id();
}

void BaseObject::decrement_id(){
    bObj_id_counter.decrement_id();
}

side question... is it possible to compare the memory adresses (this should be a unique id enough) of the objects instead of using an id_holder?

Upvotes: 2

Views: 228

Answers (5)

mfontanini
mfontanini

Reputation: 21900

Is it true that for every constructor call there will be a corresponding destructor?

Yes, unless you allocate objects using operator new and don't destroy them, or, that your application ends abnormally.

Your solution should work well, unless you use it concurrently. You should provide exclusive access to that global object if you do so, though i don't think this is the case.

is it possible to compare the memory adresses (this should be a unique id enough) of the objects instead of using an id_holder

You could do it, every object will have a unique memory address. It's a kind of dirty solution, depending on what is your objective.

Upvotes: 4

Chad
Chad

Reputation: 19032

This is typically called "reference counting" and it has a wide range of uses. Yes it is possible to do, but yours won't quite work correctly just yet.

  1. If you want a global unique identifier for all your objects, you would need to have one id held statically, and then use the curiously recurring template pattern to ensure that this id is global only for specific types. Then each type gets a copy of the global id during construction.
  2. You need to increment the counter in the copy-constructor
  3. Since increment_id() and decrement_id() are called by the id_holder class, there is no reason to call them again in your BaseObject constructor/destructor.
  4. It will not work in the presence of multithreaded access, you need to find a way to atomically set the "reference count".

This is a relatively elegant solution that allows for you to do things like constant-time lookups for an item given its ID. For example:

Warning pseudo-code (not compiled or tested)

template <class T>
class counter
{
   static size_t global_id_;
   size_t id_;

public:
    counter() : id_(global_id_++) {}
    counter(const counter&) : id_(global_id++) {}
    ~counter() {}

    counter& operator=(const counter&)
    {
      // left as an exercise for the reader
      // as what to do in this case is highly 
      // dependent upon the application
    }
};

class counted_object : public counter<counted_object>
{
   // stuff
};

Now you could hold a lookup table of counted_objects stored in a vector for very quick lookups:

std::vector<counted_object*> lookup;
counted_object* o416 = lookup[416];

Upvotes: 1

lucian.pantelimon
lucian.pantelimon

Reputation: 3669

Yes, it is, and yes you can compare the addresses. Only problem is if you have memory leaks and the objects don't get deleted.

Every object has a unique address. Even if you create an empty class or struct, it's size will not be zero(by language design). Be careful when passing the this reference from a constructor when working with multiple threads, as your object might not be fully constructed.

EDIT: You can use this to your advantage to discover memory leaks. Assuming you delete every object you have created by the time the program exits (like a clean-up method), just see if you have any objects left.

EDIT2: Here's a very good article on object counting in C++

Upvotes: 0

Sid
Sid

Reputation: 7631

  1. Yes, there will be a destructor for every class and the compiler will give you a default if you don't provide one. Look at C++ default destructor

    1. Although you can use memory addresses, it's not recommended. Can get quite obfuscating, espc. if using shared ptrs and such.

Upvotes: 0

hc_
hc_

Reputation: 2628

No, that is not necessarily true. In every well behaved program there is a destructor call for every constructor call. But if, for example, objects constructed with new aren't deleted, there will be no destructor call.

Also, in your example you didn't implement a copy constructor which means, that you might account for more destructor calls than constructor calls.

Further, you didn't implement an assignment operator, either. If the default one is used, the object being assigned to will have the same unique_id as the one being assigned from. (Assuming, unique_id is a memeber of BaseObject which you didn't declare in your code snippet.) So that would make your unique_id quite "un-unique". ;-)

Upvotes: 3

Related Questions