How can I insure that the objects of a class must be allocated in the heap?

P

PengYu.UT

Hi,

Maybe this is an simple question. How can I insure that the objects of
a class must be allocated in the heap?

Thanks,
Peng
 
J

John Harrison

Hi,

Maybe this is an simple question. How can I insure that the objects of
a class must be allocated in the heap?

Thanks,
Peng

Make all the constructors private and then declare friend functions to
allocate objects

class X
{
private:
X();
X(int, int);
X(const X&);
public:
...
friend X* make_X() { return new X(); }
friend X* make_X(int a, int b) { return new X(a, b); }
friend X* copy_X(X* rhs) { return new X(*rhs); }
};

john
 
A

Alf P. Steinbach

* (e-mail address removed):
Maybe this is an simple question. How can I insure that the objects of
a class must be allocated in the heap?

There are two ways: (1) restrict access to constructors _and_ provide
factory functions for all relevant constructors in all relevant classes,
or (2) restrict access to your destructor.

(1)
is covered in the FAQ -- go find! ;-)

(2)
which I like much better (less work, doing things once and for all), at
least until someone tells me what the Big Drawback is, is partially
covered in section 1.3.1 of <url:
http://home.no.net/dubjai/win32cpptut/special/pointers/preview/pointers_01__alpha3.doc.pdf>

In addition to the discussion there -- it's an unfinished document --
you'd probably be a happier and more productive programmer if the
once-and-for-all support includes something like

template<
typename T,
void (*defaultDestructionFunction)(T*) = &::callDelete said:
class SharedPtr: public boost::shared_ptr<T>
{
private:
typedef boost::shared_ptr<T> Base;
public:
// Ordinary construction:
SharedPtr(): Base() {}
SharedPtr( Base const& r ) throw(): Base( r ) {}
SharedPtr( T* p ): Base( p, defaultDestructionFunction ) {}
template< typename Destroyer >
SharedPtr( T* p, Destroyer d ): Base( p, d ) {}

// Special converting construction:
template< class Y >
SharedPtr( boost::shared_ptr<Y> const& r ) throw(): Base( r ) {}
template< class Y >
explicit SharedPtr( boost::weak_ptr<Y> const& r ): Base( r ) {}
template< class Y >
explicit SharedPtr( std::auto_ptr<Y>& r ): Base( r ) {}
};
 
K

Kai-Uwe Bux

Hi,

Maybe this is an simple question. How can I insure that the objects of
a class must be allocated in the heap?

First, I do not quite understand, why you would want to do something like
that.

As for how you could go about it, here is an idea: You can make the
constructors private. Now, that sounds silly as it prevents construction.
However, you can have a friend. This way, only the friend class is able to
construct objects. If that friend happens to only allocate objects via new,
then you are fine. E.g.:


#include <algorithm>
#include <iostream>

class handle;

class forbidden {

friend class handle;

int i;

forbidden ( int j = 0 )
: i ( j )
{
std::cout << "created\n";
}

~forbidden ( void ) {
std::cout << "destroyed\n";
}

forbidden ( forbidden const & other );
forbidden& operator= ( forbidden const & other );

public:

int get ( void ) const {
return ( i );
}

int set ( int j ) {
i = j;
return j;
}

}; // class forbidden

class handle {

forbidden* ptr;

public:

handle ( int i = 0 )
: ptr ( new forbidden ( i ) )
{}

handle ( handle const & other )
: ptr ( new forbidden ( other.get() ) )
{}

~handle ( void ) {
delete ptr;
}

handle & operator= ( handle const & other ) {
handle dummy ( other );
std::swap( this->ptr, dummy.ptr );
return ( *this );
}

int get ( void ) const {
return ( ptr->get() );
}

int set ( int i ) {
return( ptr->set(i) );
}

}; // handle

int main ( void ) {
handle x ( 5 );
std::cout << x.get() << '\n';
}


Note that this handle has value semantics. It is quite easy to implement
reference semantics instead.



If you just want to allow pointers to forbidden object but not forbidden
objects, you could do something like this:

#include <algorithm>
#include <iostream>

struct handle;

class forbidden {

friend class handle;

int i;

forbidden ( int j = 0 )
: i ( j )
{
std::cout << "created\n";
}

forbidden ( forbidden const & other );
forbidden& operator= ( forbidden const & other );

public:

int get ( void ) const {
return ( i );
}

int set ( int j ) {
i = j;
return j;
}

~forbidden ( void ) {
std::cout << "destroyed\n";
}

}; // class forbidden

struct handle {

static
forbidden* new_forbidden ( int i = 0 ) {
return( new forbidden ( i ) );
}

}; // handle

int main ( void ) {
forbidden* f_ptr = handle::new_forbidden ( 5 );
std::cout << f_ptr->get() << '\n';
delete f_ptr;
}



Anyway, it just seems like you want to make life harder for the clients of
your code. Generally, that is not a good idea: next week, someone will post
the question as to how your measures can be circumvented.


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

* Kai-Uwe Bux:
First, I do not quite understand, why you would want to do something like
that.

For example, a recursive data structure can/should have a recursive
cleanup operation, which needs all objects to be dynamically allocated.

As for how you could go about it, here is an idea: You can make the
constructors private.

See my earlier reply in this thread for a code-it-once-and-for-all
alternative that, so far!, I like much better... ;-)

In addition to what I wrote there, there is a tools issue: for a class
Foo the Visual 7.1 compiler incorrectly allows it to be used as a member
in a class Bar that doesn't define a destructor, but the compiler issues
a warning, and class Bar will generate errors on all practical usage.
 
K

Kai-Uwe Bux

Alf said:
* Kai-Uwe Bux:

For example, a recursive data structure can/should have a recursive
cleanup operation, which needs all objects to be dynamically allocated.

Hm, I see what you mean.

However, in such a case, I would probably have some container type and some
node type. The node type would be invisible to the clients of the
container. In that case, I do not see any reason to make myself go through
hoops to make sure that I never create a local node variable (which
actually could be useful, provided you know what you are doing). Usually, I
feel no urge to tie my hands.

On the other hand, there might be dynamic data structures in client
territory, not mediated through iterators. For those, I can see that you
have a valid point. But aren't those dangerous anyway?


Thanks

Kai-Uwe Bux
 
G

Greg

Kai-Uwe Bux said:
Hm, I see what you mean.

However, in such a case, I would probably have some container type and some
node type. The node type would be invisible to the clients of the
container. In that case, I do not see any reason to make myself go through
hoops to make sure that I never create a local node variable (which
actually could be useful, provided you know what you are doing). Usually, I
feel no urge to tie my hands.

On the other hand, there might be dynamic data structures in client
territory, not mediated through iterators. For those, I can see that you
have a valid point. But aren't those dangerous anyway?

Although not very common, there are instances when requiring
heap-allocated storage for an object is a necessity. These cases
usually arise whenever an object's lifespan extends beyond the current
scope, or the object is shared across threads or is a member of a
cache.

Relying on every programmer to "know" that a certain class of object
must be allocated on the heap is a surefire way for the program to end
up with a stack-allocated object someday. The reason would be that it
is often not apparent when any of the three situations mentioned above
may apply to an object (or at least not apparent to anyone who hasn't
spent years working on the program). So there has to be a failsafe
mechanism that will catch bugs at the ideal time: before they have been
added to the source code.

Greg
 
K

Kaz Kylheku

Hi,

Maybe this is an simple question. How can I insure that the objects of
a class must be allocated in the heap?

The answer to your question is to fix the emotional problem that causes
you to obsess over how people will use the class that you write.

It's like asking ``How can I ensure that only jazz will ever be played
on the guitar that I am building?''
 
P

Protoman

Use a singleton and make sure that the static copy that all the
references refer to is allocated on the heap.
 
P

__PPS__

Hi,
The answer to your question is to fix the emotional problem that causes
you to obsess over how people will use the class that you write.

It's like asking ``How can I ensure that only jazz will ever be played
on the guitar that I am building?''


That's not the same at all and there's no emotional problems with that.
Read previous post by Greg, where he precisely describes cases where
you just have to insure that objects are only heap-allocatable; or,
sometime later, perfectly valid code will behave unexpectedly
 
K

Kai-Uwe Bux

Greg said:
[snip]

Although not very common, there are instances when requiring
heap-allocated storage for an object is a necessity. These cases
usually arise whenever an object's lifespan extends beyond the current
scope, or the object is shared across threads or is a member of a
cache.

That objects may need to be dynamically allocated is true. However, I have a
hard time to picture a clear cut case, where that is a reasonable
requirement for *all* objects of a given class type. That, however, is the
issue here.
Relying on every programmer to "know" that a certain class of object
must be allocated on the heap is a surefire way for the program to end
up with a stack-allocated object someday.

Here you make a sweeping generalization from object to class of objects.
The reason would be that it
is often not apparent when any of the three situations mentioned above
may apply to an object (or at least not apparent to anyone who hasn't
spent years working on the program). So there has to be a failsafe
mechanism that will catch bugs at the ideal time: before they have been
added to the source code.


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top