Pointer containers and raw arrays of pointers

Greetings. I've been wrestling with some legacy C code which makes heavy use of raw arrays of pointers-- typically pointers to quasi-OO C structures which have specific "constructor" and "destructor" functions. Here's a contrived example: struct OldStuff { ... }; OldStuff* CreateOldStuff(); void DestroyOldStuff(OldStuff*); Then there are functions which return zero or more of these structures as output via an array of pointers: bool FiddleWithStuff(OldStuff** output, size_t count, ...); It's the callers responsibility to properly dispose of the results returned in 'output' by calling DestroyOldStuff() on each element. What I'd like to be able to do is provide a wrapper for functions like this which provide automatic management for the output values. Here's an example using ptr_vector: struct OldStuff_Destroyer { // What's up with the const pointer to deallocate?!? static void deallocate_clone(const OldStuff* p) { DestroyOldStuff(const_cast<OldStuff*>(p)); } }; typedef boost::ptr_vector< boost::nullable<OldStuff>, OldStuff_Destroyer> StuffVec_t; bool Wrapper(StuffVec_t& output, size_t count, ...); The pointer containers like ptr_vector seem to be a good fit, particularly given the customizable cloning behavior and is a very natural transition from an array of pointers. The problem I'm having is how to couple ptr_vector to the legacy code which expects to use arrays of pointers. Here's what I'd like to do: bool Wrapper(StuffVec_t& output, size_t count, ...) { // Won't work: resize() isn't supported output.resize(count); // Won't work: no way to get to raw storage return FiddleWithStuff(&output[0], count, ...); } As noted, this won't work for a couple of reasons. The pointer containers have an aversion to containing NULL pointers, which is why I imagine resize() isn't supported. And there's no way to get a pointer to the raw storage for the pointers to provide a buffer for the legacy code to write into. I do understand why the pointer containers don't support what I'm trying to do here, and the restrictions are entirely reasonable to provide additional safety. But... Using a container of smart pointers isn't an option, either, for the same reason: the need to have legacy code write into the storage as if it were an array. Does anyone have any suggestions on how to encapsulate a collection of pointers and some associated deletion logic? Obviously I could write my own pointer collection that satisfies my requirements, but I was hoping to use off-the-shelf bits. Thanks for any ideas. -Chris

Chris Newbold skrev:
Greetings. I've been wrestling with some legacy C code which makes heavy use of raw arrays of pointers-- typically pointers to quasi-OO C structures which have specific "constructor" and "destructor" functions. The problem I'm having is how to couple ptr_vector to the legacy code which expects to use arrays of pointers. Here's what I'd like to do:
bool Wrapper(StuffVec_t& output, size_t count, ...) { // Won't work: resize() isn't supported output.resize(count);
This seems to be an oversight as the function should be available if the container allows nulls, as your's does. What you can do for now is to roll your own using push_back()/erase().
// Won't work: no way to get to raw storage return FiddleWithStuff(&output[0], count, ...); }
Well, it's ugly, but you can do something along reinterpret_cast<OldStuff**>( &*output.begin().base() )
As noted, this won't work for a couple of reasons. The pointer containers have an aversion to containing NULL pointers, which is why I imagine resize() isn't supported. And there's no way to get a pointer to the raw storage for the pointers to provide a buffer for the legacy code to write into.
I do understand why the pointer containers don't support what I'm trying to do here, and the restrictions are entirely reasonable to provide additional safety. But...
I'm working on better C-array integration for the next release. -Thorsten

on Mon Jul 16 2007, Thorsten Ottosen <thorsten.ottosen-AT-dezide.com> wrote:
// Won't work: no way to get to raw storage return FiddleWithStuff(&output[0], count, ...); }
Well, it's ugly, but you can do something along
reinterpret_cast<OldStuff**>( &*output.begin().base() )
You should almost never recommend reinterpret_cast, as its semantics are (mostly) implementation-defined. You probably mean to static_cast twice, passing through void* -- Dave Abrahams Boost Consulting http://www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

On Mon, 16 Jul 2007 17:38:13 +0200, Thorsten Ottosen wrote:
Well, it's ugly, but you can do something along
reinterpret_cast<OldStuff**>( &*output.begin().base() )
Thanks for the reply. Is this guaranteed to work (at least in the case of ptr_vector)? I recall seeing a comment you made in the context of a discussion about the defunct ptr_begin(), etc. family of functions that there was no reliable, portable cast from void* to T* and that the pointer containers were now using void* storage. If you know that a T* went into a given void*, I've always figured that reinterpret_cast<T*> would get it back out again. Am I missing something? -Chris
participants (3)
-
Chris Newbold
-
David Abrahams
-
Thorsten Ottosen