Reputation: 24121
I have a function which I want to use to convert an array of doubles to a vector of doubles:
std::vector<double> ArrayToVector(const double* arr, int length)
{
std::vector<double> vec(length);
memcpy(&vec[0], &arr[0], length);
return vec;
};
But when I run:
int main()
{
double* x = new double[3];
x[0] = 2;
x[1] = 4;
x[2] = 6;
std::vector<double> y = ArrayToVector(x, 3);
for (int i = 0; i < 3; i++)
{
std::cout << y[i] << " ";
}
return 0;
}
I get the output:
0 0 0
Rather than
2 4 6
Why?
Upvotes: 2
Views: 7250
Reputation: 136385
Do not use memcpy
to copy into a std::vector
, it is less efficient and error prone.
It is less efficient because when you construct or resize a vector it fills new elements with a value-initialized element (unless you provide one), which is 0 for arithmetic types. But that initialization is unnecessary because you then overwrite the values. That initialization may be cheap, but it is not free.
std::vector
has a constructor that takes two iterators, as others already mentioned, that copies the input range. This constructor avoids the unnecessary default-initialization before copying.
std::vector
also has assign
and insert
member functions that take two iterators and copy the input range efficiently. v.append(beg, end)
is v.insert(v.end(), beg, end)
.
In my opinion, using memset
, memcpy
and memmov
in C++ code is always a mistake.
These functions are implemented by the standard C library and hence lose input argument type/alignment information (because they take void*
). Before switching to the most appropriate SIMD version they need to check the alignment and size of the arguments at run-time. The unaligned beginnings and ends are handled by non-SIMD instructions.
Whereas a C++ compiler knows the alignments and sizes from the type and generates appropriate SIMD instructions inline without those alignment and size checks that C library functions do. Again, those checks may be cheap, but they are not free.
C++ algorithms like std::copy
, std::copy_backward
, std::fill
and container copy functions which take two iterators use these C primitive functions for POD types automatically.
C++ initializer expressions like {}
in double buf[N] = {};
do memset
for you, but again, in a more efficient and a less error prone manner.
Upvotes: 3
Reputation: 206667
You need to use:
memcpy(&vec[0], &arr[0], length*sizeof(double));
or better yet, use:
int main()
{
double* x = new double[3];
x[0] = 2;
x[1] = 4;
x[2] = 6;
std::vector<double> y(x, x+3);
for (int i = 0; i < 3; i++)
{
std::cout << y[i] << " ";
}
return 0;
}
Upvotes: 2
Reputation: 311048
memcpy copies bytes. So you have to specify the number of bytes (not the number of doubles) you are going to copy.
memcpy(&vec[0], &arr[0], length * sizeof( double ) );
Nevertheless this approach is bad. It is better to define the vector the following way
std::vector<double> ArrayToVector(const double* arr, int length)
{
return { arr, arr + length };
}
Or
std::vector<double> ArrayToVector(const double* arr, int length)
{
std::vector<double> vec( arr, arr + length );
return vec;
}
Take into account that you need to free allocated memory for the array. You could use for example smart pointer std::unique_ptr
for the allocated array.
Upvotes: 1
Reputation: 15916
Your problem is memcpy expect a size in bytes, not number of elements so you need to multiply that third argument by sizeof(double)
but really what you should be doing is use the constructor for vector which expects two iterators like so :
std::vector<double> y(x, x + 3);
this way you don't even need to worry about sizeof and it's shorter!
Alternatively you could use std::copy
(as mentioned in my comment/the other answer but that's longer for no reason)
Upvotes: 6