Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping dynamic array into STL/Boost container?

I need to wrap a dynamically allocated array(from a = new double[100] for example) into std::vector(preferably) without copying the array. This restriction is imposed by that the array I want to wrap is mmaped from a file, so just doing vector(a, a+size) will double the memory usage.

Is any tricks to do that?

like image 953
Anton Kazennikov Avatar asked Nov 11 '09 07:11

Anton Kazennikov


3 Answers

One of the best solutions for this is something like STLSoft's array_proxy<> template. Unfortunately, the doc page generated from the source code by doxygen isn't a whole lot of help understanding the template. The source code might actually be a bit better:

  • http://www.stlsoft.org/doc-1.9/array__proxy_8hpp-source.html

The array_proxy<> template is described nicely in Matthew Wilson's book, Imperfect C++. The version I've used is a cut-down version of what's on the STLSoft site so I didn't have to pull in the whole library. My version's not as portable, but that makes it much simpler than what's on STLSoft (which jumps through a whole lot of portability hoops).

If you set up a variable like so:

int myArray[100];

array_proxy<int> myArrayProx( myArray);

The variable myArrayProx has many of the STL interfaces - begin(), end(), size(), iterators, etc.

So in many ways, the array_proxy<> object behaves just like a vector (though push_back() isn't there since the array_proxy<> can't grow - it doesn't manage the array's memory, it just wraps it in something a little closer to a vector).

One really nice thing with array_proxy<> is that if you use them as function parameter types, the function can determine the size of the array passed in, which isn't true of native arrays. And the size of the wrapped array isn't part of the template's type, so it's quite flexible to use.

like image 180
Michael Burr Avatar answered Nov 15 '22 10:11

Michael Burr


A boost::iterator_range provides a container-like interface:

// Memory map an array of doubles:
size_t number_of_doubles_to_map = 100;
double* from_mmap = mmap_n_doubles(number_of_doubles_to_map);

// Wrap that in an iterator_range
typedef boost::iterator_range<double*> MappedDoubles;
MappedDoubles mapped(from_mmap, from_mmap + number_of_doubles_to_map);

// Use the range
MappedDoubles::iterator b = mapped.begin();
MappedDoubles::iterator e = mapped.end();
mapped[0] = 1.1;
double first = mapped(0);

if (mapped.empty()){
    std::cout << "empty";
}
else{
    std::cout << "We have " << mapped.size() << "elements. Here they are:\n"
       << mapped;
}
like image 20
Éric Malenfant Avatar answered Nov 15 '22 10:11

Éric Malenfant


I was once determined to accomplish the exact same thing. After a few days of thinking and trying I decided it wasn't worth it. I ended up creating my own custom vector that behaved like std::vector's but only had the functionality I actually needed like bound checking, iterators etc.

If you still desire to use std::vector, the only way I could think of back then was to create a custom allocator. I've never written one but seeing as this is the only way to control STL's memory management maybe there is something that can be done there.

like image 2
Idan K Avatar answered Nov 15 '22 09:11

Idan K