operator new question

Get answers to all your basic programming questions. No Ogre questions, please!
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58

operator new question

Post by betajaen »

Hi,

This is a little strange to ask, but Google didn't provide an answer;

Code: Select all

class A
{
	public:

	A()
	{
		// Constructor code.
	}

	int aVariable;

	void* operator new (size_t size)
	{
		void * p = malloc(size);
		if (p == 0)
		{
			throw "Allocation failure";
		}
		A* c = (A*) p;
		c->aVariable = 10;	
		return p;
	}
};
Specifically, the setting of aVariable during the new operator. The constructor hasn't been called yet, but the memory has been allocated. Presuming that the constructor never set's aVariable, it's value is maintained. This does compiles, and does work. I just want to know is this dangerous.

The reason for why I'm doing is - is a little complicated. Let's say I'm using inheritance and a factory pattern, with macros and other nasty tricks, to set an unique id of that class.
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58

Re: operator new question

Post by CABAListic »

I have a feeling this might work on most platforms, but I wouldn't count on the standard to give you a guarantee that this will always work.

If you do not allocate your objects on separate threads in parallel, you could instead use a global variable to set in the operator new and then assign the member variable from the global in the constructor. Similarly hacky, but has a slightly more "official" feeling to it :)
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: operator new question

Post by bstone »

Really nasty, especially if you ever decide to use a container hosting your class instances that uses a custom allocator.

I don't see why you'd need that: since all the nasty things happen in the class operator new() that means you have all type information at the spot where you call that operator. That in turn means that you can simply get the id by calling a static class method, for example.
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: operator new question

Post by bstone »

Nevermind the container with a custom allocator - any static allocation would be screwed.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58

Re: operator new question

Post by betajaen »

Hmm. I'll explain a bit further on what I'm doing and the justification on why I'm doing it.

I'm writing a reflection system which works amazingly well so far, but for different type of Objects (Objects have a specific meaning in this system - it's for all classes that inherit from the class Object) a has to be unique id is given. Objects can only go in a specific type of container. Objects can never be static, or never be in non-pointer form (i.e. created without new).

This is an example of what it can do, and typical use of it;

code

Code: Select all

class Animal : public Object
{
	declare_class(Animal)

public:
	Animal()
	{
		std::cout << "Animal Constructor" << std::endl;
		x = 1001;
	}

	~Animal()
	{
		std::cout << "Animal Destructor" << std::endl;
	}

	int x;
};

define_class(Animal, t)
{
	t.member("x", &Animal::x);
}

void main()
{
	Animal* animal = new Animal();
	animal->inspect();
	delete animal;
}
result

Code: Select all

Animal Constructor
Animal.id=0
Animal.x=1001
Animal Destructor
Anyway, 'id' is an int, stored in Object. I completely realize I could just go through the normal route and set it in Object constructor, but I'd like to use operator new for other things, such as class registration and removal, instead of using 'createAnimal', 'destroyAnimal' methods, or more abstract 'storeObject', 'removeObject' method.

My end goal is to have separate automatic container templated classes for Animal, Plant, Rock, etc. which automatically register and remove instances of these classes. I can't do this in the scope of Object (because it's not a template, and I can't get the Type), and I don't want to do it in the Animal constructor, even if I had a macro. Using the operator new (and operator delete) this way, ensures I can set a unique id, and then register and de-register the class before the constructor or destructor is called.
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: operator new question

Post by bstone »

As long as you only allocate instances dynamically that should work as expected. The C++ standard guarantees that uninitialized class members having built-in types are not initialized by default since it's an important performance consideration. The only exception to that are POD structures in C++11 but your classes will not be classified as PODs (b/c long as they inherit from Object and have methods).

It still has a nasty flavor to it. I'd consider something like:

Code: Select all

template< class T >
class ObjectImpl
    : public Object
{
  public:
    ObjectImpl()
    {
        id = static_cast< T* >( this )->staticId();
    }
};

class Animal
    : public ObjectImpl< Animal >
{
  public:
    static int staticId() { return 10; }
};
That will give you per-class ids. You can improve that further with an automatic generation of unique ids if needed. You can also add some other init/shutdown logic to ObjectImpl<> with all compile-time type information at your hands. I think that might be more practical because operator delete() is invoked after all destructors for example.
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58

Re: operator new question

Post by betajaen »

That isn't a bad solution.

I always thought that if you didn't explicitly call the constructor of a parent class, it wasn't called. Which is why I went this route. I was wrong. This way is very do-able.

Thank you.

p.s. I'm hoping to post my reflection code soon, for others to use it. It isn't exactly brilliant, but it may be useful for some people.
User avatar
Mikachu
Gnoll
Posts: 603
Joined: Thu Jul 28, 2005 4:11 pm
Location: Nice, France
x 35

Re: operator new question

Post by Mikachu »

betajaen wrote:I'm hoping to post my reflection code soon, for others to use it. It isn't exactly brilliant, but it may be useful for some people.
I may be interested :)

I already made a try at reflection (here, there and there) but it remained at a prototype level.
I also read about Ogre's property component, but it only works with getter/setters and has no direct member binding (I'd like to have the choice between both), so I'm eager to see another stance on the subject :wink:
OgreProcedural - Procedural Geometry for Ogre3D
User avatar
betajaen
OGRE Moderator
OGRE Moderator
Posts: 3447
Joined: Mon Jul 18, 2005 4:15 pm
Location: Wales, UK
x 58

Re: operator new question

Post by betajaen »

Sure. Here is a copy of it, of as last week.

It can bind member variables, invoke class functions, even 'foreach' over a class. It can also export a class, struct, pod or container to an XML file as well. I'm using boost for some of it (just the identification of types of classes), and everything auto-registers as you use it - so no need to have enums, or some type ID system.

It's 'okay', but I think I can write it better, which is why I'm doing 'version 3' right now, which I'm hoping is smaller and more straightforward. I'd like to do properties as well, C# style if possible. I have a few ideas for that, but my main aim is to have proper unassisted serialisation.
You do not have the required permissions to view the files attached to this post.