5

I am writing a memory-managing template class in which I want to create a C-style array of fixed size, to serve as a heap. I keep the objects stored in an array like this:

T v[SIZE];

As this only serves the role as a heap that can hold T objects, I don't want the T default constructor to get automatically called for every object in the array.

I thought about the solution to define the heap like this:

char v[SIZE * sizeof(T)];

...but this will give me alignment problems.

Is there any better way to achieve this?

ADD: As I have special run time requirements, it is essential that this class doesn't do any allocations on the global heap.

ADD 2: SIZE is a template argument and known at compile-time.

4
  • When do you intend the T constructors to be called if not then? Manually when you allocate the array items, or are you using your own new operators? Commented Feb 16, 2010 at 14:06
  • You can use malloc, but, and again, BUT - you should not need this kind of functionality. Commented Feb 16, 2010 at 14:09
  • The T constructors will be called manually. That part is not a problem. Commented Feb 16, 2010 at 14:14
  • You should really check out boost::object_pool or boost::pool. I think they already do what you're wanting. boost.org/doc/libs/1_34_0/libs/pool/doc/interfaces.html Commented Feb 16, 2010 at 21:45

6 Answers 6

6

The standard containers use allocators to seperate allocation/deallocation from construction/destruction. The standard library supplies a single allocator which allocates on the heap.

This code declares an array big enough to hold SIZE elements of type T with the correct allignment:

typedef typename std::tr1::aligned_storage<sizeof(T),std::tr1::alignment_of<T>::value>::type aligned_storage;
aligned_storage array[SIZE];

The solution using std::allocator can't be used to declare an array on the stack, and as the standard containers require that custom allocators hold no state, a custom allocator can't be portably used to allocate on the stack either.

If your compiler doesn't support std::tr1::alignment_of you can use boost::alignment_of instead.

Sign up to request clarification or add additional context in comments.

4 Comments

I realize this is probably the best solution. Unfortunately I am prevented from using tr1 or boost. Thanks
In that case, you can look at how boost::alignment_of works - it's pretty simple conceptually, just a wrapper around a union of integer types with size <= sizeof(T). The difficulty is in providing the list of types of different sizes on different platforms. If you're only dealing with one or two compilers it should be straightforward.
The problem is that a functionality like aligned_storage requires some compiler support or at least some compiler- and machine-specific guarantees that are not part of the standard. That's why I'd keep using boost::aligned_storage (so I don't have to deal with implementation specifics).
Yes, but the questioner doesn't have access to boost, so that's not an option for him.
2

What you are looking for is called an Allocator. A good overview can be found here: http://www.codeproject.com/KB/cpp/allocator.aspx

1 Comment

I am not sure I can apply it in this case. It is essential that the manager object doesn't do any allocations and can be put on the stack.
0

What I'd probably do is create an array of char (about like you've already considered), but allocate enough space for one more object than you really need. You'll then need to write a bit of code to find the correct alignment for your objects in that space.

The largest alignment requirement for an object is its own size (otherwise arrays of those objects couldn't be contiguous, which is required). Therefore, you pick the first address in the char-buffer that's a multiple of sizeof(T), and start your array from there.

Comments

0

Weird, but should work:

long long v[size * sizeof(T)/sizeof(long long)+1];

This buffer will be alligned on 64 bits. But better will be allocate memory by new.

In any case, if size is variable - compiller will allocate memory dynamically through malloc/new (and not on stack).

EDIT: You can't use std::auto_ptr to automaticaly free buffer. Instead scoped_arr from boost can be used

6 Comments

Thanks. I should have mentioned, size is a template argument aswell.
You can't use std::auto_ptr to free a dynamically allocated array because it uses delete not delete[].
@Joe Gauterin: Excellent point. Boost has scoped_arr and shared_arr that could be used for this.
You can use the shared_ptr for the TR1. One of the constructor types allows you to specify the function that releases the object. If you have a compiler that supports C++ lambda syntax, this is a very clean solution.
But if you want a dynamically sized array, why not just stick with std::vector?
|
0

You can use a struct to handle the alignment issue.

struct Tbuffer { char data_[ sizeof( T ) ]; }

struct Tbuffer heap[ SIZE ];

2 Comments

Why not? I use this all the time.
I would be really surprised if allocating char[4] would ensure 4 byte alignment.
0

How I probably will do it (after looking on EASTL fixed_vector implementation):

PRAGMA_PRE_ALIGN(sizeof(T)) char[SIZE * sizeof(T)]; PRAGMA_POST_ALIGN(sizeof(T))

...and implement compiler specific PRAGMA_PRE_ALIGN and PRAGMA_POST_ALIGN macros, that insert the correct #pragmas.

Unfortunately, boost and tr1 are not possible for this project.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.