horstman@sjsumcs.sjsu.edu (Cay Horstmann) (12/04/90)
One of my students just had the bright idea to abuse the placement syntax of the new operator new (p) X(...); to overload X::operator new( size_t, void* ) and feed something entirely different into p than the "placement address". I told her that was a subversive idea, but then I looked into the ARM and saw that it is possible to overload X::operator new( size_t, int) and make a call new(7) X(...). Is this stuff actually useful? I guess someone must have thought it is. I grant that the placement operation has its use, but I was always mystified by its syntax. I mean, if you call the destructor explicitly with p->~X(), why not call the constructor explicitly with p->X(...) instead of new(p) X(...) (provided nobody tinkered with the definition of X::operator new().) Any info (preferably by e-mail; I'll summarize if there is interest) would be greatly appreciated. Hate mail too... Cay
cline@cheetah.ece.clarkson.edu (Marshall Cline) (12/05/90)
In article <1990Dec4.062015.6637@sjsumcs.sjsu.edu> horstman@sjsumcs.sjsu.edu (Cay Horstmann) writes: >One of my students just had the bright idea to abuse the placement syntax >of the new operator > new (p) X(...); >to overload X::operator new( size_t, void* ) and feed something entirely >different into p than the "placement address". >I told her that was a subversive idea, but then I looked into the ARM and >saw that it is possible to overload X::operator new( size_t, int) and make >a call new(7) X(...). >Is this stuff actually useful? >I guess someone must have thought it is. I grant that the placement operation >has its use, but I was always mystified by its syntax. I mean, if you call the >destructor explicitly with > p->~X(), >why not call the constructor explicitly with > p->X(...) >instead of > new(p) X(...) >(provided nobody tinkered with the definition of X::operator new().) >Any info (preferably by e-mail; I'll summarize if there is interest) would >be greatly appreciated. Hate mail too... >Cay Cay always has such colorful expressions (`abuse the placement syntax', `subversive idea', etc)!! As usual in C++, generality rules. Ie: it seems more general to allow new(size_t, any other parameters at all); than to restrict it to new(size_t, void*); Ie: if I want to allow people to allocate objects of class X by some pseudo-index, why not allow ``new(size_t,int)'' Or if I want them to allocate X's from some pool of memory, why not ``new(size_t,Pool&)'' etc. The problem with all this is that the *client* must remember where the object came from, and delete has only one syntax. The ARM (p.65-6) discusses the possibility of having a matching placement deletion syntax, but argues that it requires the client to remember all this stuff, so that the client has to choose the right deletion routine. Page 66 discusses an alternative which dispatches based on the actual type of an `Arena' or `Pool' of memory. Unfortunately this still requires the client to remember whence an object cometh. I suppose a sufficiently concerned supplier could overload operator new so that it remembers the actual Arena/Pool. A corresponding operator delete would then use that Arena/Pool. But an object isn't `born' until its ctor builds it from the raw bits returned from `new', and it dies during the dtor, which is before `delete' tries to peek at the cached `Pool*'. Any better solutions? Marshall Cline -- PS: If your company is interested in on-site C++/OOD training, drop me a line! PPS: Career search in progress; ECE faculty; research oriented; will send vita. -- Marshall Cline / Asst.Prof / ECE Dept / Clarkson Univ / Potsdam, NY 13676 cline@sun.soe.clarkson.edu / Bitnet:BH0W@CLUTX / uunet!clutx.clarkson.edu!bh0w Voice: 315-268-3868 / Secretary: 315-268-6511 / FAX: 315-268-7600
horstman@sjsumcs.sjsu.edu (Cay Horstmann) (12/05/90)
In article <CLINE.90Dec4111352@cheetah.ece.clarkson.edu> cline@sun.soe.clarkson.edu (Marshall Cline) writes: (in response to my query why (a) there is the very general scheme of overloading operator new( size_t, any other parameters ) and (b) the corresponding delete syntax is not symmetric. > >Cay always has such colorful expressions (`abuse the placement syntax', >`subversive idea', etc)!! > >As usual in C++, generality rules. Ie: it seems more general to allow > new(size_t, any other parameters at all); >than to restrict it to new(size_t, void*); > >Ie: if I want to allow people to allocate objects of class X by some >pseudo-index, why not allow ``new(size_t,int)'' > >Or if I want them to allocate X's from some pool of memory, why not >``new(size_t,Pool&)'' > >etc. > >The problem with all this is that the *client* must remember where the >object came from, and delete has only one syntax. The ARM (p.65-6) >discusses the possibility of having a matching placement deletion >syntax, but argues that it requires the client to remember all this >stuff, so that the client has to choose the right deletion routine. > >Page 66 discusses an alternative which dispatches based on the actual >type of an `Arena' or `Pool' of memory. Unfortunately this still >requires the client to remember whence an object cometh. > >I suppose a sufficiently concerned supplier could overload operator >new so that it remembers the actual Arena/Pool. A corresponding >operator delete would then use that Arena/Pool. But an object isn't >`born' until its ctor builds it from the raw bits returned from `new', >and it dies during the dtor, which is before `delete' tries to peek at >the cached `Pool*'. > Yep, this is all very true. Indeed, operator new could place information into a "header" area of the block which an overloaded operator delete could find (by subtracting the header size from this...) My student was working on the idea of implementing several pools of memory, and she passed the address of a pool descriptor into new. So there is a possible use, I guess. I do realize that placement is useful. IF one agrees that new(p) X(...) is a good syntax for placement, then it is indeed reasonable to implement the more general new(...) X(...). Personally, I don't think this is very elegant. I would much favor the symmetric syntax p->X(...) to run X::X(...) on the preallocated p and p->~X(...) on the destructor, and separately deal with the allocation and deallocation of p. Orthogonality of language features. (You know, like in Algol 68 :-)) I do realize that it is against the spirit of constructors to run them on preallocated memory (but so is an explicit call to a destructor), and there- fore a yucky syntax may discourage some from doing so. Don't bet on it, though. You'll begin to see plenty "new(this) X() // clear the state " in student's code, I bet. Has anyone used the flexibility of operator new( size_t, ... ) for anything BUT placement? Cay
dlw@odi.com (Dan Weinreb) (12/06/90)
In article <CLINE.90Dec4111352@cheetah.ece.clarkson.edu> cline@cheetah.ece.clarkson.edu (Marshall Cline) writes:
The problem with all this is that the *client* must remember where the
object came from, and delete has only one syntax. The ARM (p.65-6)
discusses the possibility of having a matching placement deletion
syntax, but argues that it requires the client to remember all this
stuff, so that the client has to choose the right deletion routine.
This is all true. However, sometimes you have an object in which you
want to control how it is allocated (e.g. you want it to live in
special shared virtual memory or something like that), for all
instances of the class. So all instances are always allocated the
same way, and so you can just write one operator delete that does the
appropriate deletion. The parameterization of operator new is still
useful. This is only a special case, of course; in general you'd like to
be able to allocate some objects one way and some another way, and not
have the problem with delete. But it is a useful special case.
sking@nowhere.uucp (Steven King) (12/06/90)
In article <1990Dec5.155604.24463@sjsumcs.sjsu.edu> horstman@sjsumcs.sjsu.edu (Cay Horstmann) writes: >Yep, this is all very true. Indeed, operator new could place information >into a "header" area of the block which an overloaded operator delete could >find (by subtracting the header size from this...) > >My student was working on the idea of implementing several pools of memory, >and she passed the address of a pool descriptor into new. So there is a >possible use, I guess. > >I do realize that placement is useful. > >IF one agrees that new(p) X(...) is a good syntax for placement, then it is >indeed reasonable to implement the more general new(...) X(...). > >Personally, I don't think this is very elegant. I would much favor the symmetric >syntax p->X(...) to run X::X(...) on the preallocated p and p->~X(...) on the >destructor, and separately deal with the allocation and deallocation of p. > >Orthogonality of language features. (You know, like in Algol 68 :-)) > >I do realize that it is against the spirit of constructors to run them on >preallocated memory (but so is an explicit call to a destructor), and there- >fore a yucky syntax may discourage some from doing so. Don't bet on it, though. > >You'll begin to see plenty "new(this) X() // clear the state " in student's >code, I bet. > >Has anyone used the flexibility of operator new( size_t, ... ) for anything >BUT placement? A real world ;-} usage; An embedded system consisting of a central host and multiple coprocessors. Communication between the host and the copros are via dualport ram. Messages are of variable length, but of a common base format. class Message defines the common header shared by all derived messages and an operator new ( but not delete ), which is inherited by all derived message classes. Message::operator new is passed a reference to a "comm" which is an object containing the desired dualport area which itself exists as a "heap" object which has two methods, alloc and free ( actually void * heap::operator ( ) ( size_t ) and void heap::operator ( ) ( void * ) -- I have a lot of fun finding new uses of operator ( ) ( ) ;-). Operator message::new calls the heap alloc method which synchronizes access to the heap ( it is a shared resource in a multitasking system ) and actually allocates the space in the dualport. The delete operator is not defined because one of comm's methods that functions as an interrupt handler simply invokes the heap free method on the message -- by definition, if the comm interrupt handler services a message, it must belong to that comms heap. kinda nasty, but it gets around the limited delete syntax. And of course comm::operator new invokes the constructor for the dualport class which does a ram check on the dualport and initializes the coprocessor, returning the result code in the third arguement to comm::new, a reference to an int... I had lots of fun with this code. The placement form of new is also usefull if one wants to create an array of objects but doesnt want to use a default constructor. class A { public: A ( int ) ; } ; main() { char buf [ 10 * sizeof ( A ) ] ; int i = 0 ; for ( char *b = buf ; b < buf + 10 * sizeof ( A ) ; b+= sizeof ( A ) ) new ( b ) A ( i++ ) ; } I'm sure there are other ways to abuse overloading new that I havent thought of yet... -- sking@nowhere ..!cs.utexas.edu!ut-emx!nowhere!sking been dazed and confused for so long its true; wanted an OS, never bargined for you. Lotsa people hacking, few of them know, kernal of unix was created below...