D
Daniel T.
"Jack said:Thank you Daniel, that sounds like a good idea. If I provide only
constructors that take a destructor function as a parameter, the user must
provide one in order to use my Buffer class. Do you think the following code
would be correct? Is it portable? Does memory alignment work in it?
using namespace std;
template<class T>
class Buffer
{
public:
Buffer(T* p, size_t ElemSize size_t ArraySize, void(*pfn)(T*)) :
_p(ArraySize), _i(ElemSize), _pfn(pfn)
{
void* u=reinterpret_cast<void*>(p);
for(size_t j=0;j<ArraySize;++j)
{
_p[j]=reinterpret_cast<T*>(u);
u+=ElemSize;
}
}
~Buffer() { (*pfn)(&_p[0]); }
T& operator[](size_t i) { return *_p; }
const T& operator[](size_t i) const { return *_p; }
private:
vector<T*> _p;
size_t _i;
void(*_pfn)();
};
Regards,
Jack
Please try to compile your code before posting...
But you are on to something. Here is your code corrected. What makes it
work is the templated constructor...
template < class Base >
class Buffer
{
Buffer( const Buffer& );
Buffer& operator=( const Buffer& );
public:
template < typename Derived >
Buffer( Derived* p, size_t ArraySize, void(*pfn)(void*) )
: _memory( p )
, _p( ArraySize )
, _pfn( pfn )
{
for ( int i = 0; i < ArraySize; ++i )
_p = &p;
}
~Buffer() { (*_pfn)(_memory); }
Base& operator[](size_t i) { return *_p; }
const Base& operator[](size_t i) const { return *_p; }
private:
void* _memory;
vector<Base*> _p;
void(*_pfn)(void*);
};
void kill( void* p ) { }
void kill2( void* p ) {
B* b = reinterpret_cast<B*>( p );
delete [] b;
}
int main() {
B b[20];
Buffer<A> buf( &b[0], 20, &kill );
assert( &buf[0] == &b[0] );
assert( &buf[1] == &b[1] );
B* b2 = new B[5];
Buffer<A> buf2( b2, 5, &kill2 );
assert( &buf2[0] == &b2[0] );
assert( &buf2[1] == &b2[1] );
}
Your loosing some type safety though, and the Buffer has to maintain an
extra pointer per object over a more conventional approach.
Also, copying Buffers would be problematic, which is why I disable it.