Getting Array from Std:Vector

Getting array from std:vector

This was discussed in Scott Meyers' Effective STL, that you can do &vec[0] to get the address of the first element of an std::vector, and since the standard constrains vectors to having contiguous memory, you can do stuff like this.

// some function
void doSomething(char *cptr, int n)
{

}

// in your code
std::vector<char> chars;

if (!chars.empty())
{
doSomething(&chars[0], chars.size());
}

edit: From the comments (thanks casablanca)

  • be wary about holding pointers to this data, as the pointer can be invalidated if the vector is modified.

How to initialize std::vector from C-style array?

Don't forget that you can treat pointers as iterators:

w_.assign(w, w + len);

How to convert vector to array

There's a fairly simple trick to do so, since the spec now guarantees vectors store their elements contiguously:

std::vector<double> v;
double* a = &v[0];

Converting between C++ std::vector and C array without copying

You can get a pointer to the first element as follows:

int* pv = &v[0];

This pointer is only valid as long as the vector is not reallocated. Reallocation happens automatically if you insert more elements than will fit in the vector's remaining capacity (that is, if v.size() + NumberOfNewElements > v.capacity(). You can use v.reserve(NewCapacity) to ensure the vector has a capacity of at least NewCapacity.

Also remember that when the vector gets destroyed, the underlying array gets deleted as well.

Copy std::vector into std::array

Use std::copy_n

std::array<T, N> arr;
std::copy_n(vec.begin(), N, arr.begin());

Edit: I didn't notice that you'd asked about moving the elements as well. To move, wrap the source iterator in std::move_iterator.

std::copy_n(std::make_move_iterator(v.begin()), N, arr.begin());

How do you copy the contents of an array to a std::vector in C++ without looping?

If you can construct the vector after you've gotten the array and array size, you can just say:

std::vector<ValueType> vec(a, a + n);

...assuming a is your array and n is the number of elements it contains. Otherwise, std::copy() w/resize() will do the trick.

I'd stay away from memcpy() unless you can be sure that the values are plain-old data (POD) types.

Also, worth noting that none of these really avoids the for loop--it's just a question of whether you have to see it in your code or not. O(n) runtime performance is unavoidable for copying the values.

Finally, note that C-style arrays are perfectly valid containers for most STL algorithms--the raw pointer is equivalent to begin(), and (ptr + n) is equivalent to end().

std::vector versus std::array in C++

std::vector is a template class that encapsulate a dynamic array1, stored in the heap, that grows and shrinks automatically if elements are added or removed. It provides all the hooks (begin(), end(), iterators, etc) that make it work fine with the rest of the STL. It also has several useful methods that let you perform operations that on a normal array would be cumbersome, like e.g. inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes).

Since it stores the elements in memory allocated on the heap, it has some overhead in respect to static arrays.

std::array is a template class that encapsulate a statically-sized array, stored inside the object itself, which means that, if you instantiate the class on the stack, the array itself will be on the stack. Its size has to be known at compile time (it's passed as a template parameter), and it cannot grow or shrink.

It's more limited than std::vector, but it's often more efficient, especially for small sizes, because in practice it's mostly a lightweight wrapper around a C-style array. However, it's more secure, since the implicit conversion to pointer is disabled, and it provides much of the STL-related functionality of std::vector and of the other containers, so you can use it easily with STL algorithms & co. Anyhow, for the very limitation of fixed size it's much less flexible than std::vector.

For an introduction to std::array, have a look at this article; for a quick introduction to std::vector and to the the operations that are possible on it, you may want to look at its documentation.



  1. Actually, I think that in the standard they are described in terms of maximum complexity of the different operations (e.g. random access in constant time, iteration over all the elements in linear time, add and removal of elements at the end in constant amortized time, etc), but AFAIK there's no other method of fulfilling such requirements other than using a dynamic array. As stated by @Lucretiel, the standard actually requires that the elements are stored contiguously, so it is a dynamic array, stored where the associated allocator puts it.

std::vector as raw array

C++11 (and C++03 for that matter) guarantees that the data in std::vector are contiguous. This means, that in your case, &my_vector[0] can be thought of as the pointer to the zeroth element of that array and normal pointer arithmetic can be used to access the other elements. It's preferred to use my_vector.data() to recover the pointer to the zeroth element.

C++98 almost guarantees it.

Note that it's not true for std::vector<bool> for any of the C++ standards. This is because std::vector<bool> is implemented as a particular specialisation.

Most efficient way of getting large std::vector into Swift?

Some parts are not clear enough but I will try to show you some example.

First of all, you need to prepare a class which can access your contourVector. (I cannot see if it is an instance field or a global variable, if it is an instance field, you may use the existing class.)


Create a header for the prepared class, again you may utilize the existing header, but this header needs to be compiled both in C-context and in C++ context. So, if your existing header contains some declaration which cannot be compiled in C-context, you may need separated two headers or some #ifs.

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface YourClass : NSObject

- (NSInteger)contoursSize;
- (NSInteger)contourSizeAtIndex:(NSInteger)index;
- (CGPoint *)contourAtIndex:(NSInteger)index;

//...

@end

NS_ASSUME_NONNULL_END

Then add 3 methods to the class specified in the header:

#import "YourClass.h"
#import <vector>

typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;

static CGContours contourVector;

@implementation YourClass

- (NSInteger)contoursSize {
return contourVector.size();
}
- (NSInteger)contourSizeAtIndex:(NSInteger)index {
return contourVector[index].size();
}
- (CGPoint *)contourAtIndex:(NSInteger)index {
return contourVector[index].data();
}

@end

Please do not forget to include the header inside your Project-Bridging-Header.h:

//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "YourClass.h"

You need to create a Swift side wrapper class, as you cannot create UnsafeBufferPointer in Objective-C.

class YourClassWrapper {
let yourInstance = YourClass()

var count: Int {
return yourInstance.contoursSize()
}

subscript(index: Int) -> UnsafeBufferPointer<CGPoint> {
guard 0..<count ~= index else {fatalError("Index \(index) out of bounds \(0..<count)")}
let start = yourInstance.contour(at: index)
let count = yourInstance.contourSize(at: index)
return UnsafeBufferPointer(start: start, count: count)
}
}

With these preparations above, you can access each CGPoint as:

let wrapper = YourClassWrapper()
let point = wrapper[0][1]

Or you can get the pointer to the first element in CGContour as:

let ptr = wrapper[0].baseAddress!

You may need to modify some parts to fit this into your actual code. Hope you can make it.

vectorvector? to array in C++

You're on the right track with the .data() member function, but that would give you an array of objects of type std::vector<T>, not an array of objects of type T. To truly flatten a nested vector you will need to do it yourself. Something like this would probably do the trick.

// 1. Compute the total size required.
int total_size = 0;
for (auto& vec : vectors) total_size += vec.size();

// 2. Create a vector to hold the data.
std::vector<T> flattened;
flattened.reserve(total_size);

// 3. Fill it
for (auto& vec : vectors)
for (auto& elem : vec)
flattened.push_back(elem);

// 4. Obtain the array
auto ptr = flattened.data();

For older compilers, you can iterate through the vectors like so

for (std::vector<std::vector<T> >::iterator iter = vectors.begin();
iter != vectors.end(); ++iter) {
for (std::vector<T>::iterator iter2 = iter->begin();
iter2 != iter->end(); ++iter2) {
flattened.push_back(*iter2);
}
}

Or just use plain old indices and the .size() member function.

Internally, std::vector holds on to a pointer to its elements, and so the outermost data() must conceptually be treated like an array of pointers, not a 2D array. Therefore we have to manually walk through and flatten it.



Related Topics



Leave a reply



Submit