Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Arrays of derived objects

Reply
Thread Tools

Arrays of derived objects

 
 
Jack
Guest
Posts: n/a
 
      03-20-2006
> I'm not sure what you really intend for Buffer. If it is a lightweight
> as it appears, then I don't see it's usefulness over a std::vector. You
> say it manages the the allocation and deallocation, yet your
> implementation certainly does not manage the allocation.


I am sorry if I have said that. It does not manage the allocation (only
deallocation). Because the client code is the only one that knows the exact
type of the managed objects, it must do the allocation.

The usefulness over a std::vector would be the ability of indexing objects
of the derived type. std::vector can index only objects that are exactly of
the type that is given as a template parameter to it.

> Could you describe the problem you are trying to solve, rather than
> describing the implementation (with Buffer)?


I am writing a library which should support code reuse. It contains a class
A which is a general interface for particular operations. All components in
this library shall be able to perform their tasks through this interface A
(so they shall not be aware of any classes derived from A). The library also
contains this Buffer class, which manages arrays of objects that implement
this interface A. But the actual implementation is client-dependent (class B
that is derived from class A) so the actual objects managed by the Buffer
are of type B (but the Buffer knows only that they implement the interface
A).

Regards,

Jack


 
Reply With Quote
 
 
 
 
Jack
Guest
Posts: n/a
 
      03-20-2006
Yes, I also thought of this solution. The problem is that either I would
need reinterpret_cast which may be unportable, or, if I give Buffer the
responsibility to do the allocation, I would need to give it the type of the
derived objects. Giving the type of the derived objects to Buffer as a
template parameter makes the whole Buffer useless because then the other
components in the library cannot use it any longer (they don't know how to
instantiate a Buffer object).

However, that is the best solution so far. If anybody knows a better one,
please let me know.

Jack


 
Reply With Quote
 
 
 
 
Ben Pope
Guest
Posts: n/a
 
      03-20-2006
Jack wrote:
>> I'm not sure what you really intend for Buffer. If it is a lightweight
>> as it appears, then I don't see it's usefulness over a std::vector. You
>> say it manages the the allocation and deallocation, yet your
>> implementation certainly does not manage the allocation.

>
> I am sorry if I have said that. It does not manage the allocation (only
> deallocation). Because the client code is the only one that knows the exact
> type of the managed objects, it must do the allocation.


It is often prudent to tie allocation and deallocation of a resource
together, synchronised with the lifetime of an object. This principle
has spawned many a smart-pointer. (Look up RAII).

> The usefulness over a std::vector would be the ability of indexing objects
> of the derived type. std::vector can index only objects that are exactly of
> the type that is given as a template parameter to it.


OK, well:
std::vector<A*>

>> Could you describe the problem you are trying to solve, rather than
>> describing the implementation (with Buffer)?

>
> I am writing a library which should support code reuse. It contains a class
> A which is a general interface for particular operations. All components in
> this library shall be able to perform their tasks through this interface A
> (so they shall not be aware of any classes derived from A).


OK, Fine.

> The library also
> contains this Buffer class, which manages arrays of objects that implement
> this interface A.


If Buffer just manages arrays of, and allows polymorphic access to
elements of arrays, then it would seem somewhat of a utility; rather
orthogonal to the other part of the library.

That's not a problem in itself.

> But the actual implementation is client-dependent (class B
> that is derived from class A) so the actual objects managed by the Buffer
> are of type B (but the Buffer knows only that they implement the interface
> A).


OK, I'm pretty sure you want this to be irrelevant to the implementation
of Buffer.

Have you seen the boost pointer containers? I think they will solve
your problem.
http://www.boost.org/libs/ptr_contai...container.html

A ptr_array (statically sized) does pretty much what you want, I think.
The only thing missing is allocation-in-one.

I haven't checked this will work, but perhaps you could allocate a B
array, and then use ptr_array::replace to make it's pointers point to
the objects in your array.

You know what? Get it working first. If the x news are too slow, then
try new [x].

Ben Pope
--
I'm not just a number. To many, I'm known as a string...
 
Reply With Quote
 
Jack
Guest
Posts: n/a
 
      03-20-2006
> It is often prudent to tie allocation and deallocation of a resource
> together, synchronised with the lifetime of an object. This principle
> has spawned many a smart-pointer. (Look up RAII).


I know.

> > The usefulness over a std::vector would be the ability of indexing

objects
> > of the derived type. std::vector can index only objects that are exactly

of
> > the type that is given as a template parameter to it.

>
> OK, well:
> std::vector<A*>


Yes, this is a "multiple calls to new with memory leaks" solution. With
smart pointers (for example, the ones in the Boost library) it is the
"multiple calls to new" solution.

> If Buffer just manages arrays of, and allows polymorphic access to
> elements of arrays, then it would seem somewhat of a utility; rather
> orthogonal to the other part of the library.


True. Actually it is part of another library I am writing, but I thought
that that detail is irrelevant in the point of view of my problem.

> > But the actual implementation is client-dependent (class B
> > that is derived from class A) so the actual objects managed by the

Buffer
> > are of type B (but the Buffer knows only that they implement the

interface
> > A).

>
> OK, I'm pretty sure you want this to be irrelevant to the implementation
> of Buffer.


True again.

> Have you seen the boost pointer containers? I think they will solve
> your problem.
> http://www.boost.org/libs/ptr_contai...container.html
>
> A ptr_array (statically sized) does pretty much what you want, I think.
> The only thing missing is allocation-in-one.
>
> I haven't checked this will work, but perhaps you could allocate a B
> array, and then use ptr_array::replace to make it's pointers point to
> the objects in your array.


No. ptr_array::replace handles only single elements, so this is just one
more variation of the "multiple calls to new" solution.

> You know what? Get it working first. If the x news are too slow, then
> try new [x].


Yes, trying should always be done before code optimization process. In this
case there will be tens of thousands of objects, so it is pretty obvious
that new[] will be more efficient. Generally, when you have to handle
multiple small objects the memory pool idiom should be used. The solution
presented by Jakob Bieling resembles that idiom, but its weakness is the
type unsafety.

I am thankful for your trying to help. But even better solutions will be
welcome

Regards,

Jack


 
Reply With Quote
 
Ben Pope
Guest
Posts: n/a
 
      03-20-2006
Jack wrote:
>
>> Have you seen the boost pointer containers? I think they will solve
>> your problem.
>> http://www.boost.org/libs/ptr_contai...container.html
>>
>> A ptr_array (statically sized) does pretty much what you want, I think.
>> The only thing missing is allocation-in-one.
>>
>> I haven't checked this will work, but perhaps you could allocate a B
>> array, and then use ptr_array::replace to make it's pointers point to
>> the objects in your array.

>
> No. ptr_array::replace handles only single elements, so this is just one
> more variation of the "multiple calls to new" solution.


....not if you preallocate the array, and replace the pointers... It's
one call to new and a bunch of pointer assignments

>> You know what? Get it working first. If the x news are too slow, then
>> try new [x].

>
> Yes, trying should always be done before code optimization process. In this
> case there will be tens of thousands of objects, so it is pretty obvious
> that new[] will be more efficient. Generally, when you have to handle
> multiple small objects the memory pool idiom should be used. The solution
> presented by Jakob Bieling resembles that idiom, but its weakness is the
> type unsafety.


Providing your own allocator and/or operator new for the derived type
could certainly help.

> I am thankful for your trying to help. But even better solutions will be
> welcome


OK, last ditch attempt

You seem to think that you cannot provide Buffer, templated on the
derived type to the user. I'm not sure this is the case, but I'll have
to accept your word on that.

The fundamental problem then, is knowing the size of the array to be
deallocated. If you know the size of an element (pretty sure you cannot
to that polymorphically, i.e., you need to know the derived type, or at
least sizoef(b)), you can allocate a block of memory, and call placement
new for each element.

In the destructor, you can call the destructor of each element in the
array, and then delete the block you allocated.

What that gains you over over providing the derived type in the
template, is that it is run time. A call to the constructor might look
like:

Buffer b<A>(sizeof(B), 5);

I see no way around requiring the derived type *somewhere*.

Ben Pope
--
I'm not just a number. To many, I'm known as a string...
 
Reply With Quote
 
Daniel T.
Guest
Posts: n/a
 
      03-20-2006
In article <B3vTf.109$>, "Jack" <>
wrote:

> Hi,
>
> Is there a general solution for the following problem:
>
> I have an array of instances of class B. Class B is publicly derived from
> class A. Then I have a class named Buffer that generally takes care of
> allocating and deallocating arrays. Class Buffer knows only that the objects
> contained in its internal array are derived from class A but not that they
> are exactly of type B, so Buffer has a member variable of type A* that
> points at the beginning of that array. I know that indexing the elements
> will not work with this mechanism, so I should rather have one more level of
> indirection, that is, an array of elements of type A* that point to each B
> object. But I think (please correct me if I am wrong) that the need to
> allocate each object B separately slows down the operation, so I would like
> to use new[] once instead of new multiple times. Okay, I can use first new
> B[...] and then set one A* element in the array to point at each instance of
> B. But is that sensible? Is there another way? Will delete[] clean up the
> memory correctly if the pointer type given to it does not exactly match the
> type of the elements contained in the array? (I mean, if the array of
> objects B is deleted in the destructor of Buffer that knows only that the
> elements are derived from class A)
>
> I don't want to use virtual functions in class Buffer, because they cause
> overhead in speed. I don't want to templatize it either, because it should
> be enough for it to know that the objects contained in its internal array
> are derived from class A. But still it should be able to index the elements
> and destroy them correctly. What is the best way to do it?
>
> Thank you very much for your help in advance,


Unfortunately, as you have already deduced from earlier posts, you can't
get there.

If you insist on all the objects allocated in a C array, you will have
to know the exact type in order to delete [] the array, since you can't
know that...

Here is an idea... Have your static library hold a vector of A*s and
document that the user of your library must both new and delete the A*
objects. Then he can put them in a buffer or not at his whim.



--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
 
Reply With Quote
 
Jack
Guest
Posts: n/a
 
      03-20-2006
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[i]; }
const T& operator[](size_t i) const { return *_p[i]; }

private:
vector<T*> _p;
size_t _i;
void(*_pfn)();
};

Regards,

Jack


 
Reply With Quote
 
Daniel T.
Guest
Posts: n/a
 
      03-20-2006
In article <7yxTf.152$>,
"Jack" <> wrote:

> > I'm not sure what you really intend for Buffer. If it is a lightweight
> > as it appears, then I don't see it's usefulness over a std::vector. You
> > say it manages the the allocation and deallocation, yet your
> > implementation certainly does not manage the allocation.

>
> I am sorry if I have said that. It does not manage the allocation (only
> deallocation). Because the client code is the only one that knows the exact
> type of the managed objects, it must do the allocation.
>
> The usefulness over a std::vector would be the ability of indexing objects
> of the derived type. std::vector can index only objects that are exactly of
> the type that is given as a template parameter to it.


That's where you are confused, vector can do everything that a C array
can do. Since a C array cannot index objects of the derived type,
neither can vector.

Try it your self and see:

class A {
int X;
};

class B : public A {
int y;
};

int main() {
B array[2];
A* ptr = array;
assert( ptr == &array[0] );
++ptr;
assert( ptr == &array[1] ); // this will fail
}

> > Could you describe the problem you are trying to solve, rather than
> > describing the implementation (with Buffer)?

>
> I am writing a library which should support code reuse. It contains a class
> A which is a general interface for particular operations. All components in
> this library shall be able to perform their tasks through this interface A
> (so they shall not be aware of any classes derived from A). The library also
> contains this Buffer class, which manages arrays of objects that implement
> this interface A. But the actual implementation is client-dependent (class B
> that is derived from class A) so the actual objects managed by the Buffer
> are of type B (but the Buffer knows only that they implement the interface
> A).


The client will have to both create and destroy the B objects that the
buffer's elements point to.

If you insist on the buffer deleting the elements, then each element
must be allocated individually, not as part of a B array.


--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
 
Reply With Quote
 
Jack
Guest
Posts: n/a
 
      03-20-2006
No, I do not mean that the Buffer class would do the indexing that (regular)
way. If it did, then there would not be any value in it, because a C array
(and a std::vector) can do the same. In the Buffer class the purpose is to
do some tricks so that the indexing will work. And my question is what the
best way to do those tricks is

Please take a look at the code in my reply posting to your other message.
There I have shown a sample code of what I mean. And yes, I know there are a
couple of syntax errors because I did not try to compile it, but anyway it
should illustrate the idea.

Jack

> > The usefulness over a std::vector would be the ability of indexing

objects
> > of the derived type. std::vector can index only objects that are exactly

of
> > the type that is given as a template parameter to it.

>
> That's where you are confused, vector can do everything that a C array
> can do. Since a C array cannot index objects of the derived type,
> neither can vector.
>
> Try it your self and see:
>
> class A {
> int X;
> };
>
> class B : public A {
> int y;
> };
>
> int main() {
> B array[2];
> A* ptr = array;
> assert( ptr == &array[0] );
> ++ptr;
> assert( ptr == &array[1] ); // this will fail
> }



 
Reply With Quote
 
Jack
Guest
Posts: n/a
 
      03-20-2006
Ben, if you take a very careful look at all these postings once again you
will notice that all those ideas had already been discussed in this thread.
Thanks for your help anyway

Jack


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Multidimensional arrays and arrays of arrays Philipp Java 21 01-20-2009 08:33 AM
Derived::Derived(const Base&) and Derived& operator=(const Base&) developereo@hotmail.com C++ 1 05-23-2007 01:44 PM
Derived::Derived(const Base&) developereo@hotmail.com C++ 4 05-23-2007 09:32 AM
Derived::Derived(const Base&) and Derived& operator=(const Base&) developereo@hotmail.com C++ 1 05-23-2007 12:07 AM
Arrays of derived objects - newbie Robert C++ 5 01-14-2007 12:13 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57