views:

307

answers:

6

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?

+2  A: 

No, that is not possible using a std::vector.

But if possible you can create the vector with this size, and possible map the file to that instead.

std::vector<double> v(100);
mmapfile_double(&v[0], 100);
dalle
+1  A: 

What about vector of pointers that point to your mapped area elements (reduced memory consumption as sizeof(double*) < sizeof(double))? Is this OK for you?

There is some drawbacks (primary is you need special predicates for sort) but some benefits too as you can, for example, delete elements without changing actual mapped content (or have even number of such arrays with different order of elements without any change to actual values).

There is common problem of all the solutions with std::vector on mapped file: to 'nail' vector content to mapped area. This can't be tracked, you can only watch after yourself to not use something which could lead to vector content re-allocation. So be careful in any case.

Roman Nikitchenko
+1  A: 

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.

Idan K
I suggest not writing an own container. It's most of the time simply not worth it and leads to quite a few interoperatibility issues. Additionally, time spent on debugging reinvented stuff is wasted time.The custom allocator however is probably quite easy to implement and a better approach.
MP24
Normally I would agree, but I really think it depends what you're going to do with it. Most of the "complex" operations in std::vector probably have something to do with memory management and it happens that in this case none of them are required. So writing a small class with bounds checking and a pointer as an iterator shouldn't take too long. I can't comment on interoperatbility since I have no knowledge of where/how the author intends to use it. But iterator support should make it work with STL's algorithms.
Idan K
+7  A: 

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:

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.

Michael Burr
+1, seems to be best solution, especially because proxy should not reallocate memory so it should be free from many problems.
Roman Nikitchenko
+2  A: 

You could go with array_proxy<>, or take a look at Boost.Array . It gives you size(), front(), back(), at(), operator[], etc. Personally, I'd prefer Boost.Array since Boost is more prevalent anyway.

imran.fanaswala
+2  A: 

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;
}
Éric Malenfant