tags:

views:

775

answers:

4

I am experimenting with OpenCL to increase the speed of our software. We work with maps a lot and, to simplify, represent a map as a std::vector< std::vector >. The OpenCL API takes raw c-style pointers as arguments, for example int* in the case above.

My questions:

  • Are there implementation guarantees in the stl that vector is, internally, consecutive in memory?
  • Can I safely cast a std::vector to int* and expect that to work?
  • In the case of a vector of vectors, can I still assume this holds true? I would expect the vector to hold other state data, or alignment issues, or maybe something else...
  • What is the best way to approach this? Write a custom 2d data structure that holds an internal, contiguous-in-memory buffer and work with that? I'd have to copy to/from vectors a lot...

Thanks.

+2  A: 

Are there implementation guarantees in the stl that vector is, internally, consecutive in memory?

Although I cannot quote the standards here, I have seen code in high-quality libraries assuming this layout (namely, POCO).

Can I safely cast a std::vector to int* and expect that to work?

Specifically, you cannot recast the vector itself. But, I have seen the following code:

std::vector<int> vec;
int* ptr = &vec[0];

In the case of a vector of vectors, can I still assume this holds true? I would expect the vector to hold other state data, or alignment issues, or maybe something else...

You probably cannot cast a vector of vectors to a linear array. Each vector will reserve its own memory range and you cannot expect all of these ranges to be sequencial.

Ferdinand Beyer
you can't cast an iterator to a pointer
jalf
Ferdinand Beyer
+12  A: 

Are there implementation guarantees in the stl that vector is, internally, consecutive in memory?

As of C++03, yes, a vector is guaranteed to use contiguous storage. (In C++98, there was an accidental loophole so an implementation could hypothetically use non-contiguous storage, but it was fixed in the 2003 revision of the standard - and no implementation actually used non-contiguous storage because it'd be a terrible idea)

Can I safely cast a std::vector to int* and expect that to work?

The usual way is &v[0]. (&*v.begin() would probably work too, but I seem to recall there's some fluffy wording in the standard that makes this not 100% reliable)

No. Why would you expect that to work? A vector is a class. It is not a pointer. It just contains a pointer.

In the case of a vector of vectors, can I still assume this holds true? I would expect the vector to hold other state data, or alignment issues, or maybe something else...

The vector behaves the same whatever you store in it. If you make a vector of vectors, you end up with an object which contains a pointer to a heap-allocated array, where each element is an object which contains a pointer to a heap-allocated array.

As for how you should approach this, it depends on a lot of factors. How big is your total dataset? You might want to have the entire table allocated contiguously. With a vector of vectors, each row is a separate allocation.

jalf
Thank you. Indeed I phrased my question wrong, I meant 'cast first element to pointer' rather than 'cast vector itself', or 'address of vector itself'. Anyway it seems like there is no way to easily work with the raw contents of a vector of vectors, I'll have to rethink the way I work with the data. Typical size is between 500x500xsizeof(unsigned char) and 2500x2500xsizeof(double), and then 20 to 50 of those, so pretty big.
Roel
Boost.MultiArray would do the job for you nicely. Alternatively, I'd just allocate it as a single contiguous array or vector big enough to hold the entire 2d table
jalf
Motti
True, good point. vector<bool> is just messed up. :)
jalf
pgast
jalf
+2  A: 
  • Are there implementation guarantees in the stl that vector is,
    internally, consecutive in memory

Yes, it is a dynamic array. Standard guarantees that the objects inside vector are stored consecutively.

  • Can I safely cast a std::vector to int* and expect that to work?

No, but you can use begin() and use that as the pointer.

  • Are there implementation guarantees in the stl that vector is,
    internally, consecutive in memory

No, since vector may contain some internal member variables the whole 2D array will not be continuos memory location

Naveen
Pieter
+1  A: 

You mentioned in a comment that you work with up to 2500x2500xsizeof(double) data. In that case, I would suggest using one single vector instead of vector of vectors. Allocate NxM elements in a vector and wrap it in a class exposing two-dimensional indexing if you wish to. You get all the benefits of vector with minimum overhead and all your data is still in contiguous memory for fast processing.

sbk
Yes, this is probably the approach I/we should take - at least in the context of this question. The problem is that our 'map' data types also need to be able to read from different locations (over a network, from disk for maps that are too big to fit in memory (20 gigabyte maps are no exception), ... We'll just have to test a few approaches, or implement several and have a run-time selector mechanism that determines the optimal behaviour on the user's machine/problem set. Anyway thanks for your comment.
Roel