views:

256

answers:

8

I'm having a function which gets an input buffer of n bytes, and needs an auxillary buffer of n bytes in order to process the given input buffer.

(I know vector is allocating memory at runtime, let's say that I'm using a vector which uses static preallocated memory. Imagine this is NOT an STL vector.)

The usual approach is

void processData(vector<T> &vec) {
    vector<T> &aux = new vector<T>(vec.size()); //dynamically allocate memory
    // process data
}
//usage:
processData(v)

Since I'm working in a real time environment, I wish to preallocate all the memory I'll ever need in advance.

The buffer is allocated only once at startup. I want that whenever I'm allocating a vector, I'll automatically allocate auxillary buffer for my processData function.

I can do something similar with a template function

static void _processData(vector<T> &vec,vector<T> &aux) {
     // process data
}
template<size_t sz>
void processData(vector<T> &vec) {
    static aux_buffer[sz];
    vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector
    _processData(vec,aux);
}
// usage:
processData<V_MAX_SIZE>(v);

However working alot with templates is not much fun (now let's recompile everything since I changed a comment!), and it forces me to do some bookkeeping whenever I use this function.

Are there any nicer designs around this problem?

+3  A: 

I don't see how you can get precisely what you describe. Something like this could be a good compromise for you.

void processData(vector<T>& vec)
{
    static vector<T> aux(vec.size());
    if (vec.size() > aux.size()) {
       aux.resize(vec.size());
    }
    ...
}
AProgrammer
note that this moves the memory reservation from startup to first call - which might already be a problem. Also, both versions typically aren't thread safe (not sure if this is a concern for the OP)
peterchen
That's why I mentioned that it wasn't exactly what was asked. A point in favor of this solution: it doesn't have a static vector per possible size, which could be a waste.
AProgrammer
A: 

Could you create a small struct that contained your vector and an equally-sized buffer? Then you'd have your vector carry its processing buffer along with it wherever it goes. If you pass it by reference or pointer you should avoid the copying overhead. Pseudocode follows below:

struct Container
{
    vector<T> vec;
    vector<T> buf;

    Container(int size)
    {
        vec.reserve(size);
        buf.reserve(size);
    }
};

Any function that currently takes your vector argument would then take a Container.

Kristo
+1  A: 

vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector

Is that new in STL? Or a custom extension?

The typical solution would be using a custom allocator. However, this isn't necessarily "more pretty" in code.

Some intro slides (warning: powerpoint!)
Wikipedia
Google

peterchen
Quoting myself: "(I know vector is allocating memory at runtime, let's say that I'm using a vector which uses static preallocated memory. Imagine this is NOT an STL vector.)".
Elazar Leibovich
+1  A: 

Even if you succeed in doing this, it may not achieve what you want. Depending on what OS you are using and how it implements virtual memory, you may find that you get lazy allocation, where only part of your memory allocation is actually allocated and mapped initially, and further pages are mapped in later as a result of page faults. If your OS has mlock or equivalent then you may be able to work around this.

Paul R
Page faults? In real time mission critical system? I think not. Where would we store the memory pages if we have no disk? All the code should fit the memory, and stay there. Or am I missing something?
Elazar Leibovich
@Elazar: you didn't say what OS you were using, so I could only assume you're using a "common or garden" OS such as Linux. If you're using something like VxWorks (or at least an OS without VM) then it's a different story of course.
Paul R
@Paul, is vanilla Linux the "Common Garden" of real time systems? I think VxWorks deserves this title more than Linux does.
Elazar Leibovich
+1  A: 

I think you could pre-allocate and mlock() a sufficiently large memory pool on startup, and then use regular STL containers with memory pool allocators (Boost of FSBA or your own).

I was looking into that for our real-time software, but tests showed that memory allocation is fast enough on our hardware for our purposes.

Cubbi
A: 

Probably you can override the new and delete operators, but than you will have to manage your whole memory on your own. You can allocate as much memory as you want at the beginning:

void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new[] (std::size_t size) throw (std::bad_alloc);
void operator delete (void* ptr) throw ();
void operator delete[] (void* ptr) throw ();
CSpille
+1  A: 

let's say that I'm using a vector which uses static preallocated memory

Then you should be able to get size (or max size) of preallocated memory at compile-time. If such a vector had its size as template argument, then working with processData function would be easier.

template<class T, size_t sz>
class vector 
{ 
 enum { size = sz } //either max size
...
}

template<class Vector>
static void _processData(Vector &vec,Vector &aux)
{
     // process data
}
template<class Vector>
void processData(Vector &vec) {
    static aux_buffer[Vector::size];
    //no need to pass size into constructor, as Vector type knows it already
    Vector aux(aux_buffer); // use aux_buffer for the vector
    _processData(vec,aux);
}
// usage:
vector<int, 30> v1;
vector<float, 40> v2;
//no need to specify template parameter explicitly
//every call uses its own function instance and its own buffer of different size
processData(v1);
processData(v2);
Alsk
+1  A: 

It's not the vector you need to worry about, it's the memory allocator.

You could perfectly create a memory allocator which preallocates its memory and then pass it up to the vector when you build it, that's what the Alloc template parameter is for!

And to make sure that the memory is not "virtually" allocated, touch it when you allocate it.

scoped_array<byte> buffer = new byte[SIZE];
memset(buffer.get(), 0, SIZE);

Now, you "just" have to implement a custom allocator which refers to this memory pool and pass it to the vector implementation :)

Matthieu M.
@Matthieu, how would the custom allocator know how many times will I call it?
Elazar Leibovich
Custom means you program it yourself, you can thus do whatever you want as to its functionality, as for example logging the allocations and deallocations for future profiling etc...
Matthieu M.