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:
- Convert your existing codebase to use
vector
, and use expression templates to retain most of the benefits ofvalarray
. - Convert the library to use
valarray
. - 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"BJhVv
3rjrhvM"WLE3%y#N7g37Re^XiS9lpyKA9E7ow6U=I"tlv",&@+fZoIR4KM58!NTm978wCI?9wo.ocS!9i5k@ler47J.G0yXjZVSdr=G"uRodC06k\V%8;o
UwV&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
Serialize and Send a Data Structure Using Boost
Friend Declaration Declares a Non-Template Function
How to Fix: /Usr/Lib/Libstdc++.So.6: Version 'Glibcxx_3.4.15' Not Found
How to Write a Stateful Allocator in C++11, Given Requirements on Copy Construction
Why Is Std::Is_Pod Deprecated in C++20
How to Use an Enum Value in a Switch Statement in C++
Converting a Row of Cv::Mat to Std::Vector
Cannot Open Include File: 'Ctype.H': No Such File or Directory
Default Visibility of C++ Class/Struct Members
Function Pointers in Objective C
C++ Streams Confusion: Istreambuf_Iterator VS Istream_Iterator
Garbage Collection Libraries in C++
Can Using a Lambda in Header Files Violate the Odr
What Are Customization Point Objects and How to Use Them
Why Can't I Store References in a 'Std::Map' in C++
Accessing Elements of a Cv::Mat with At<Float>(I, J). Is It (X,Y) or (Row,Col)
Why Aren't Copy Constructors "Chained" Like Default Constructors and Destructors