Converting Between C++ Std::Vector and C Array Without Copying

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.

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().

How to make a std::vectorT use an existing T* array without copying those values?

There is no interface into vector to make it take ownership of your pre-existing buffer. Even if you could shoe-horn it into the vector by using a custom allocator that provides this memory's address, the vector will consider it raw memory and overwrite it.

If it must be a vector, then you're out of luck without copying.

However, some sort of adaptive view on the existing buffer could give a container-like interface over your array without copying (such as the gsl::span as suggested in comments by Justin.)

gsl::span<int> s(myPtr, 4);

see https://github.com/Microsoft/GSL
and http://codexpert.ro/blog/2016/03/07/guidelines-support-library-review-spant/

Is it possible to extract data from std::vector without copying it? (and make the vector forget it)

No, It is not possible to extract part of data from vector as far as I know.

It is not compatible with structure of vector that provides its data in a continuous part of memory. std::vector memory is continues, so if it was possible to move part of its memory to another place, you need to shift reminder of memory to keep it continuous. It will be a huge burden itself.

I personally suggest to pass main vector by pointer/reference and use required parts directly as needed.

If you need to move whole data of std::vector to another place, you can just use std::move() to do so. You can even use std::swap() to swap contents of 2 vector together.

How to move a std::vector into a raw array in C++

You can't.

A vector owns its buffer. You cannot steal it.

You will have to copy/move the elements individually, optionally using a helper algorithm that does the iteration for you (std::copy/std::move).

(Also note that, since your element type is just float, a move here is a copy.)

(Also note that this std::move, the algorithm, is not the same as std::move, the rvalue cast.)


Consider whether you really need to do this. You can treat the vector's data as an array using vec.data() whenever you need to, as long as you keep the vector alive. Surely that's better than sacrificing RAII?

Converting a valarray to a vector without copying

No, I am afraid it is not possible to convert a valarray to a vector without copying.

Your options are:

  1. Convert your existing codebase to use vector, and use expression templates to retain most of the benefits of valarray.
  2. Convert the library to use valarray.
  3. Copy.

I would start with option 3 and just copy.

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];

Appending a C-array to a vector in reverse order in C++98/03 without a for-loop

There you go. Use std::reverse_copy with std::back_inserter to add elements to the vector:

std::vector<int> vec;
int array[5] = { 1 , 2 , 3 , 4 , 5};

std::reverse_copy(array , array + 5, std::back_inserter(vec));

If you're concerned about performance, don't forget to reserve() before copying.

C++: Disassemble a flat vector into multiple vectors of equal size without copying

Yes, in my opinion this is possible. Moving the elements, but not copying the elements.

C++ offers std::make_move_iterator. Please read here about that.

To check that, I created a small class to output, to see, if we copy or move something.

So, if your data can "move", then it will work, otherwise of course a copy will be made. With the following we see the result.

struct Test {
int data{};

Test(int d) : data(d) { std::cout << "Construct and init\n"; }
Test() { std::cout << "Default construct\n"; };
~Test() { std::cout << "Destruct\n"; };
Test(const Test& other) { std::cout << "Construct\n"; data = other.data; }
Test(const Test&& other) noexcept { std::cout << "Move Construct\n"; data = other.data; }
Test& operator =(const Test& other) noexcept { std::cout << "Assign\n"; data = other.data; return *this; }
Test& operator =(const Test&& other) noexcept { std::cout << "Move Assign\n"; data = other.data; return *this; }
};

We will additionally add a small function, which calculates the offsets of the chunks that will be moved.

And then, we can come up with a small function to implement that.

#include <iostream>
#include <vector>
#include <numeric>
#include <iterator>
#include <iomanip>

// Calculate start and end index for all chunks
std::vector<std::pair<size_t, size_t>> calculatePairs(const size_t low, const size_t high, const size_t numberOfGroups) {

// Here we will store the resulting pairs with start and end values
std::vector<std::pair<size_t, size_t>> pairs{};

// Calculate chung size and remainder
const size_t delta = high - low;
const size_t chunk = delta / numberOfGroups;
size_t remainder = delta % numberOfGroups;

// Calculate the chunks start and end addresses for all chunks
size_t startIndex{}, endIndex{};
for (size_t i = 0; i < numberOfGroups; ++i) {

// Calculate end address and distribute remainder equally
endIndex = startIndex + chunk + (remainder ? 1 : 0);
// Store a new pair of start and end indices
pairs.emplace_back(startIndex, endIndex);
// Next start index
startIndex = endIndex;
// We now consumed 1 remainder
if (remainder) --remainder;
}
//--pairs.back().second;
return pairs;
}

struct Test {
int data{};

Test(int d) : data(d) { std::cout << "Construct and init\n"; }
Test() { std::cout << "Default construct\n"; };
~Test() { std::cout << "Destruct\n"; };
Test(const Test& other) { std::cout << "Construct\n"; data = other.data; }
Test(const Test&& other) noexcept { std::cout << "Move Construct\n"; data = other.data; }
Test& operator =(const Test& other) noexcept { std::cout << "Assign\n"; data = other.data; return *this; }
Test& operator =(const Test&& other) noexcept { std::cout << "Move Assign\n"; data = other.data; return *this; }
};

std::vector<std::vector<Test>> split(std::vector<Test>& v, unsigned int n) {
std::vector<std::vector<Test>> result{};
if (v.size() > n) {

result.resize(n);
std::vector<std::pair<size_t, size_t>> offset = calculatePairs(0u, v.size(), n);

for (size_t i{}; i < n; ++i) {
result[i].insert(result[i].end(), std::make_move_iterator(v.begin() + offset[i].first),
std::make_move_iterator(v.begin() + offset[i].second));
}
}
return result;
}

constexpr size_t NumberOfElements = 30u;
constexpr unsigned int NumberOfGroups = 3;
static_assert (NumberOfElements >= NumberOfGroups, "Number of elements must be greater/equal then number of elements\n");

int main() {
std::cout << "\n\n\nCreate vector with " << NumberOfElements << " elements\n\n";
std::vector<Test> v1(NumberOfElements);

std::cout << "\n\n\nFill vector with std::iota\n\n";
std::iota(v1.begin(), v1.end(), 1);

std::cout << "\n\n\nSplit in " << NumberOfGroups<< "\n\n";
std::vector<std::vector<Test>> s = split(v1, NumberOfGroups);

std::cout << "\n\n\nOutput\n\n";
for (const std::vector<Test>& vt : s) {
for (const Test& d : vt) std::cout << std::setw(3) << d.data << ' ';
std::cout << "\n\n";
}
}

But my strong guess is that you want to splice the data. The underlying elements fo the std::vector which you can get with the data() function.

You can access the data easily with pointer arithmetic on data().

But if you want to have the data in a new container, then this is difficult with a std::vector. It can for example be done with a std::list that has a splice function and does, what you want.

Or, you need to implement your own dynamic array and implement a splice function . . .


Checksum:

;23M#eTo1?:B#r7C8#wtJ'Z'..uIvLT.j;bld$Bvgjd.qm=8;B/`dHM%D@wyv:\5YI:WVGwJL00%IsKQ9O+&@g,/gzkPg^cg::LX?6dL3;Fs3GOOAmQmCIW?&skWxZXsElyn6S3@fi:0DSKJ/A^r#*'k#a#e8!XDpjAUtu?K5iu+e=P"M7a2BWdFdA.5NP:Y"l,,h+Y/PxhVfP/m0ceS=Nxol2vOZwM2+!H\^a=douX%fhqcr4'0eXiEZeKvTf0^%CTNY^WB6fc#IpK^GQgxTXQo0ikr0+/OxXlc1B$5jc1r,GQj+fwEdoCPrz6,j:SO6L3QU#7lT:f#Y^V!Au\P'a5amR$NCU?\WspBOuy#RH3tJimka#rdyNN56.$;DtRCHN*YeWlrG=',XNSrzEK:Cw;@A%.@/:c,a2W24IIIdecc7O"EnKQn;nXmUemX4kclDsYci+izmr#vlGAQ.w2!cuf;6n2UvJM,CeSyRj1,:2\9#i8GLwtux!uEHUp7X*5SC%nld956CHsy&/n73/90cRP'Me"1PW+@#FH8mH4Rf^o=ZP/Rm\X&1syUdUh+.N/jtoO:,OBBAmq,jW69Fu%jJukBa$g4hIrIPcxx17i;XU,FCbQGd8v*AyKGSML\JN#jte*F";Zh7fqhvCXobE&SapX90r"Z$.CN,1R^aj.=5L6^tUB2UPJH^eb'*B!v5=D.9PFI#Pt*KjK+yS*tV6f.5kgPOzBE$uK0MA/\l9U"63LUR6k3#'cub?u&xILMXP%@:lx2TbKhFOjBpMN!+%F16jrgv&AoFhuf%P!==8?x,NsSd%hVo"BJhVv3rjrhvM"WLE3%y#N7g37Re^XiS9lpyKA9E7ow6U=I"tlv",&@+fZoIR4KM58!NTm978wCI?9wo.ocS!9i5k@ler47J.G0yXjZVSdr=G"uRodC06k\V%8;oUwV&z!W5:+ZvE:nyO#+lO+Hn0&tnH&^tNC?'PmERxs/B+KW4O6&oWDED9?MqxmYgVKoT.a%iw

Input C++ Vector into C function

As I mentioned, I solved this problem by not using sonicChangeFloatSpeed at all, but the code within it. Before reading the results from the stream into vec, I do vec.resize(numSamples):

sonicStream stream = sonicCreateStream(16000, 1);
sonicSetSpeed(stream, speed);
sonicSetPitch(stream, pitch);
sonicSetVolume(stream, volume);
sonicSetRate(stream, rate);

auto length = static_cast<int>(vec.size());
sonicWriteFloatToStream(stream, vec.data(), length);
sonicFlushStream(stream);
int numSamples = sonicSamplesAvailable(stream);
vec.resize(numSamples);
sonicReadFloatFromStream(stream, vec.data(), length);

sonicDestroyStream(stream);


Related Topics



Leave a reply



Submit