2

I am trying to add my object pointer into vector same time object is created. Currently I have done it in object's constructor but now I have heard that this is a wrong way because object isn't completely created on that point.

MyObject class constructor:

// MyObject constructor
MyObject::MyObject() {
    // add object to vector of all objects
    MyObjectManager::Instance()->objects.push_back(this);
}

MyObject is just a base class for objects. I have also MyRectangle class that is inherited from MyObject so when I create new MyRectangle then MyObject constructor is called and my newly created object is pushed into MyObjectManager's vector.

MyObjectManager is a singleton class that keeps list of all objects and calls their virtual Draw function very frequently. Is that the problem? MyObjectManager might call object's Draw function before object is completely created?

I could make separate method for adding object to vector. Something like this:

MyObject::Create() {
    // add object to vector of all objects
    MyObjectManager::Instance()->objects.push_back(this);
}

But then I have to use it like this:

MyRectangle *rect = new MyRectangle(0.5, 0.5, 0.1, 0.1);
rect->Create();

I just want to be able to instantiate new object simply by constructor like this:

MyRectangle *rect = new MyRectangle(0.5, 0.5, 0.1, 0.1);
user19985
  • 23
  • 3

5 Answers5

2

You can do that in your constructor, isn't it?

MyRectangle::MyRectangle(const float& a, const float& b, const float& c, const float& d) {
  this->Create();
}
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • Does this work? If I call Create function inside contsructor then isn't it the same than just pushing to vector inside constructor? – user19985 Dec 13 '13 at 11:58
  • @user19985 No it is not the same. If you call Create inside MyRectangle constructor, the MyObject constructor has already been completed, then it's ok. As I told you in comments you could take a look at this answer that decribes this issue stackoverflow.com/a/3905886/356440. – Stephane Rolland Dec 13 '13 at 12:13
  • @StephaneRolland ok, thanks. And I actually read that answer but obviously didn't understand everything :) – user19985 Dec 13 '13 at 12:17
  • @user19985 if you have to remember something, constructors are called one after the other, from the base class to the sub classe, then to the sub sub class and so on. On the contrary remember that destructors are called in the reversed order. From the sub class, to the base class, to the base class until the end of the hierarchy. – Stephane Rolland Dec 13 '13 at 12:24
2

If you have special MyObjectManager class, you can use it also as a factory for objects. To illustarate it consider code:

struct MyObjectManager {

    template <typename T, typename... Args>
    T * createObject(Args... args) {
        T *ret = new T(args...);
        m_objects.push_back(ret);
        return ret;
    }

    std::vector<MyObjects *> m_objects;
};

Object creation:

MyRectangle *rect = MyObjectManager::Instance()->createObject<MyRectangle>(1.0, 2.0, 3.0, 4.0);
inkooboo
  • 2,904
  • 1
  • 19
  • 24
1

Maybe you could consider using a factory pattern:

MyRectangle * factoryMyRectangle(float x, float y, float w, float h)
{
    MyRectangle *rect = new MyRectangle(x,y,w,h);
    rect->Create();
    return rect;
}

that you can call:

MyRectangle *rect = factoryMyRectangle(0.5, 0.5, 0.1, 0.1);
Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
1

A lot depends on context. If the push_back is the last instruction in the constructor, and there are no derived classes, there should be no problem. Similarly, if you are in a single threaded environment (and since you don't do any locking, you must be), and the derived classes don't do anything through the pointer in the vector, there is no problem. You're allowed to have pointers to not yet fully-constructed objects, as long as you don't try to use the actual object they point to.

The one case where this could be a problem is if you do it in a base class constructor in a multithreaded environment. If you push the pointer to the not yes fully constructed object, and then another thread takes over, looks up the object in the vector, and tries to use it, you are in trouble. There are various techniques to handle this: the most common is probably to use a factory function to construct all objects, and have the factory function do the push_back, after the constructor has finished. So you would never call new MyRectangle(...) outside of the factory function. (Typically, the factory function will be a static member, and the constructor will be private, so you can guarantee this.)

Note that if you do use the factory function, you'll probaby want to keep the results of new in a smart pointer until the push_back has finished:

std::unique_ptr<MyRectangle> tmp( new MyRectangle(...) );
MyObjectManager::Instance()->objects.push_back( tmp.get() );
tmp.reset()
James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

If you can guarantee there will be no access but mere storage to the object before it is fully constructed, there shouldn't be a problem with using the this pointer like you did. The guarantee is broken if there is another thread handling draw updates which, for instance, polls all objects in the manager class and calls their draw function regularly.

Look at this question and this one for more information.

Community
  • 1
  • 1
Kristian D'Amato
  • 3,996
  • 9
  • 45
  • 69