Reputation: 857
I'm working with a class for which the new operator has been made private, so that the only way to get an instance is to write
Foo foo = Foo()
Writing
Foo* foo = new Foo()
does not work.
But because I really want a pointer to it, I simulate that with the following :
Foo* foo = (Foo*)malloc(sizeof(Foo));
*foo = Foo();
so that can test whether the pointer is null to know whether is has already been initialized.
It looks like it works, from empirical tests, but is it possible that not enough space had been allocated by malloc ? Or that something else gets funny ?
--- edit ---
A didn't mention the context because I was not actually sure about why they the new operator was disabled. This class is part of a constraint programming library (gecode), and I thought it may be disabled in order to enforced the documented way of specifying a model.
I didn't know about the Concrete Data Type idiom, which looks like a more plausible reason.
That allocation scheme may be fine when specifying a standard model --- in which everything is specified as CDTs in the Space-derived class --- but in my case, these instance are each created by specific classes and then passed by reference to the constructor of the class that reprensents the model.
About the reason i'm not using the
Foo f;
Foo *pf = &f;
it would be like doing case 1 below, which throws a "returning reference to local variable" warning
int& f() { int a=5; return a; } // case 1
int& f() { int a=5; int* ap=&a; return *ap; }
int& f() { int* ap=(int*)malloc(sizeof(int)); *ap=5; return *ap; }
this warning disappears when adding a pointer in case 2, but I guess it is because the compiler loses tracks.
So the only option left is case 3 (not mentioning that additionaly, ap
is a member of a class that will be initialized only once when f is called, will be null otherwise, and is the only function returning a reference to it. That way, I am sure that ap
in this case when lose its meaning because of the compilier optimizing it away (may that happen ?)
But I guess this reaches far too much beyond the scope of the original question now...
Upvotes: 3
Views: 1908
Reputation: 180305
Wrap it:
struct FooHolder {
Foo foo;
operator Foo*() { return &foo; }
};
Upvotes: 1
Reputation: 101506
Don't use malloc
with C++ classes. malloc
is different from new
in the very important respect that new
calls the class' constructor, but malloc
does not.
You can get a pointer in a couple ways, but first ask yourself why? Are you trying to dynamically allocate the object? Are you trying to pass pointers around to other functions?
If you're passing pointers around, you may be better off passing references instead:
void DoSomething(Foo& my_foo)
{
my_foo.do_it();
}
If you really need a pointer (maybe because you can't change the implementation of DoSomething
), then you can simply take the pointer to an automatic:
Foo foo;
DoSomething(&foo);
If you need to dynamically allocate the Foo
object, things get a little trickier. Someone made the new
operation private
for a reason. Probably a very good reason. There may be a factory method on Foo
like:
class Foo
{
public:
static Foo* MakeFoo();
private:
};
..in which case you should call that. Otherwise you're going to have to edit the implementation of Foo
itself, and that might not be easy or a good thing to do.
Upvotes: 8
Reputation: 87603
Be careful about breaking the Concrete Data Type idiom.
You are trying to circumvent the fact that the new
operator has been made private, i.e. the Concrete Data Type
idiom/pattern. The new
operator was probably made private for specific reasons, e.g. another part of the design may depend on this restriction. Trying to get around this to dynamically allocate an instance of the class is trying to circumvent the design and may cause other problems or other unexpected behavior. I wouldn't suggest trying to circumvent this without studying the code thoroughly to ensure you understand the impact to other parts of the class/code.
Solutions
...
Objects that represent abstractions that live "inside" the program, closely tied to the computational model, the implementation, or the programming language, should be declared as local (automatic or static) instances or as member instances. Collection classes (string, list, set) are examples of this kind of abstraction (though they may use heap data, they themselves are not heap objects). They are concrete data types--they aren't "abstract," but are as concrete as int and double.
class ScopedLock
{
private:
static void * operator new (unsigned int size); // Disallow dynamic allocation
static void * operator new (unsigned int size, void * mem); // Disallow placement new as well.
};
int main (void)
{
ScopedLock s; // Allowed
ScopedLock * sl = new ScopedLock (); // Standard new and nothrow new are not allowed.
void * buf = ::operator new (sizeof (ScopedLock));
ScopedLock * s2 = new(buf) ScopedLock; // Placement new is also not allowed
}
ScopedLock object can't be allocated dynamically with standard uses of new operator, nothrow new, and the placement new.
Upvotes: 4
Reputation: 41351
The funny thing that would happen results from the constructor not being called for *foo
. It will only work if it is a POD (simple built-in types for members + no constructor). Otherwise, when using assignment, it may not work out right, if the left-hand side is not already a valid instance of the class.
It seems, you can still validly allocate an instance on the heap with
Foo* p = ::new Foo;
To restrict how a class instance can be created, you will probably be better off declaring the constructor(s) private and only allow factory functions call them.
Upvotes: 2
Reputation: 13035
I don't have full understanding of the underlying code. If other things are ok, the code above is correct. Enough space will be allocated from malloc()
and anything funny will not happen. But avoid using strange code and work straighforward:
Foo f;
Foo *pf = &f;
Upvotes: 0