Jump to content
  • Advertisement
Sign in to follow this  
hincubator

C++: how to prevent stack object instaniation?

This topic is 5138 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I need somehow to prevent my class from stack instaniation(auto, local variables). Or on the other hand, how to distinguish between heap and stack instances at runtime. As an example: imagine container Scene, which keeps list of SceneObjects. When in Scene::addObject(SceneObject* obj); i need to know if obj is in stack or in heap. During ~Scene() i need to destroy SceneObjects in list.

Share this post


Link to post
Share on other sites
Advertisement
You could overload the new operator for that class, which then sets a global flag that the new operator was called. Then in the constructor of the SceneObject class, you check that flag, and if it is set, set another flag inside that class. Then you set the global flag to false again, so if the construct will be called for a stack var, it will set it's flag to false. Then if the Scene is destructed, you should only delete the objects which have their flag set.

You can use the same technique to not allow stack allocations alltogther, you just assert if the flag is set, and so if it not set, you will get a (runtime) error.

I don't know how it will work if the object is a normal member of another class, and you construct that class with new. I don't think the operator new of the child class will be called then, but that's probably not what you want either.

But on the other hand, I don't think this is a good idea alltogether. You better just make sure that all SceneObjects that are part of the Scene class will be allocated with new.

Share this post


Link to post
Share on other sites
To prevent objects from being created on the stack, you could make all constructors private and provide a factory function for that type of objects. This function then will give out pointers to new objects on the heap.

Share this post


Link to post
Share on other sites
Even if you could reliably do it, you'll still have problems with SceneObjects that are members of other heap-based objects. If it is the policy of Scene to take full control of all SceneObjects added to it, then document it and move on. Those sorts of hacks aren't worth the effort for people who do stupid things :)

Share this post


Link to post
Share on other sites

class Thing {
public:
static Thing* Create() { return new Thing(); }
private:
Thing() {
}
};

int main() {
Thing* pThing = Thing::Create();
delete pThing;
Thing thing;//won't compile
return 0;
}



On the whole you can't easily know whether something is stack or heap allocated. It may be that you're trying to be too clever.

Share this post


Link to post
Share on other sites
Or alternatively:
void Scene::addObject(SceneObject* obj)
{
standardContainerOfChoice.add(SmartPointer<SceneObject>(new SceneObject(*obj)));
}


Enigma

Share this post


Link to post
Share on other sites
petewood

class Thing {
public:
static Thing* Create() { return new Thing(); }
private:
Thing() {
}
};

int main() {
Thing* pThing = Thing::Create();
Thing thing = *pThing; //local //copy constructor
delete pThing;
return 0;
}

Maybe i'm trying outsmart myself. Anyway thanks guys !

Share this post


Link to post
Share on other sites
Making the copy constructor private too:
class Thing {
public:
static Thing* Create() { return new Thing(); }
private:
Thing() {
}
Thing(const Thing&) {
}
};

int main() {
Thing* pThing = Thing::Create();
delete pThing;
Thing thing;//won't compile
Thing thing = *pThing//won't compile either, now
return 0;
}

Share this post


Link to post
Share on other sites
There is no reliable way to guarantee that an object is either stack allocated or heap allocated. If you must guarantee that and object is heap allocated, implement a cloning setup. Or just properly document your containers and state that all objects inserted need to be heap allocated.

Share this post


Link to post
Share on other sites
Quote:
Original post by hincubator
Hi!
I need somehow to prevent my class from stack instaniation(auto, local variables). Or on the other hand, how to distinguish between heap and stack instances at runtime.

As an example: imagine container Scene, which keeps list of SceneObjects. When in Scene::addObject(SceneObject* obj); i need to know if obj is in stack or in heap.

During ~Scene() i need to destroy SceneObjects in list.


instead of trying to figure if an instance passed to a function is on the heap or not, enforce your scene container in managing it's elements memory, do what STL containers provide copy schematics, when a new element is added to the container copy construct the new element on the heap (or else where) so it doesn't matter if the example value was created on the stack or heap it manages its own elements, and if the type SceneObject is a polymorphic type then either A. create virtual clone and/or a create method or B. use templates & a policy creator class:

e.g. of A

#include <list>
#include <algorithm>

struct SceneObject {

virtual ~SceneObject() {}
virtual SceneObject* clone() const = 0;
virtual SceneObject* create() const = 0;

/* ... */

};

struct derived_obj : SceneObject {

derived_obj* clone() const { return new derived_obj(*this); }
derived_obj* create() const { return new derived_obj(); }

/* ... */

};

struct SceneContainer {

typedef std::list<SceneObject*> scene_list;

private:

scene_list sl;

static SceneObject* deleter(SceneObject* sc) {
delete sc; return 0;
}

public:

void add(const SceneObject& s) {

sl.push_back(s.clone());

}

/* ... */

void clear() {
std::transform(sl.begin(), sl.end(), sl.begin(), deleter);
sl.clear();
}

~SceneContainer() {
clear();
}

};

int main() {


derived_obj s;

SceneContainer sc;

sc.add(s);

}




e.g. B

#include <list>
#include <algorithm>

struct SceneObject {

virtual ~SceneObject() {}
/* ... */

};

struct derived_obj : SceneObject {

/* ... */

};

template < typename T >
struct default_creator {

static T* clone(const T& t) {
return new T(t);
}

static T* create() {
return new T();
}

static T* destroy(T* t) {
delete t; return 0;
}

};


template < template < typename U > class Creator = default_creator >
struct SceneContainer {

typedef std::list<SceneObject*> scene_list;

private:

scene_list sl;

public:


template < typename DerivedSceneObject >
void add(const DerivedSceneObject& s) {

sl.push_back(Creator<DerivedSceneObject>::clone(s));

}

/* ... */

void clear() {
std::transform(sl.begin(), sl.end(), sl.begin(), Creator<SceneObject>::destroy);
sl.clear();
}

~SceneContainer() {
clear();
}

};


int main() {


derived_obj s;

SceneContainer<> sc;

sc.add(s);

}



The latter being preferable.

Also some body mentioned about overloadeding/re-implementing global operators new/new[] & delete/delete this is not generally recommended, you can overload operators new/new[] & delete/delete for a hierarchy of types just by overloading those operators in the base type and all sub-type will use those versions. e.g:


#include <cstdlib>
#include <new>

struct foo {

void* operator new(size_t size) {
return malloc(size);
}

void operator delete(void* mem) {
free(mem);
}

virtual ~foo() {}
};

struct bar : foo {};

int main() {

foo* a = new foo; //uses foo's new
foo* b = new bar; //uses foo's new
bar* c = new bar; //uses foo's new

delete a; //uses foo's delete
delete b; //uses foo's delete
delete c; //uses foo's delete

return 0;

}


if you really need to overload for a package/component/module/library what-ever you wont to call it then overload it in a named-namespace don't overload/re-implement global ones e.g.


#include <cstdlib>
#include <new>

namespace foo {

void* operator new(size_t size) {
return malloc(size);
}

void operator delete(void* mem) {
free(mem);
}


};

struct bar {};

int main() {

using foo::operator new;
using foo::operator delete;

bar* f = new bar; //uses foo's new

delete f; //uses foo's delete


return 0;

}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!