I have a really large valarray that I need to convert to a vector because a library I'm using only takes a vector as input. I'm wondering if it's possible to convert from valarray to vector without copying. Here's what I have:
#include <vector>
#include <valarray>
int main() {
std::valarray<double> va{ {1, 2, 3, 4, 5} };
//Error: cannot convert from 'initializer list' to 'std::vector<eT,std::allocator<_Ty>>'
//std::vector<double> v1{ std::begin(va), va.size() };
//Error: cannot convert from 'std::valarray<double>' to 'std::vector<eT,std::allocator<_Ty>>'
//std::vector<double> v2{ std::move(va) };
// Works but I'm not sure if it's copying
std::vector<double> v3;
v3.assign(std::begin(va), std::end(va));
}
The documentation on assign says that the function "assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.". This sounds to me like it copies. Is there a way to do it 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 of valarray.
Convert the library to use valarray.
Copy.
I would start with option 3 and just copy.
Related
I've seen code that uses a const std::vector, however can't see why it wouldn't make more sense to simply use an std::array instead.
The values for the vector seem to be initialized at compile-time.
What is the benefit of a const std::vector?
Edit: The vector was not big, only a couple of strings, however I see that this may be one advantage.
const std::vector lets you have a "fixed sized array" whose size you only know at run time but still allows you to have all the benefits of a standard container. If you used a raw/smart pointer in your code you will need to manually pass the size of the array that it points to into the function(s) that need to know the size of the array.
The std::vector could be used with a large list of data, because it could use Dynamic Allocated Array to store values and before C++20 it's doesn't have a constexpr constructor. But std::array uses a raw C-Array and it could be used at compile time with the stack size restricted list of data. So:
std::array const is good for:
Where your data size is less than the stack size.
Where data locality is important.
You want your list at the compile time (before C++20).
std::vector const is good for:
Where your data size is large than the stack size.
It's quite common to see C++ code that expects references to vectors, sometimes const, something like this:
auto do_sum(std::vector<int> const& numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Even though the good intentions are not about not copying memory, this code require the caller to allocate a std::vector, even though the amount of value and the actual values might be known at compile time.
This might be fixed by using a span instead:
auto do_sum(std::span<int const> numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Now this code don't require the users to allocate a vector for the array, and might use std::array, or plain C arrays.
Also, sometimes you don't know what are the numbers of element the array can have, and might be determined at runtime. Consider this:
auto create_vector() -> std::vector<int> {
auto vec = std::vector<int>{};
if (/* runtime condition */) {
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
} else {
vec.push_back(4);
vec.push_back(5);
}
return vec;
}
int main() {
std::vector<int> const vec = create_vector();
}
As you can see here, as the vector is moved from scope to scope, the const-ness changes and is expressing the intent of the developer to only make it mutable in some initializing scopes.
Because the std::array needs you to specify the size as part of the type. By using std::vector the compiler can work that out for your dynamically.
This matters in maintenance situations as it prevents errors. You only add/remove a string from the initializer of the object and the vector will have the correct size automatically. If you use an array you need to add/remove the string and change the type of the array.
const std::vector<std::string> dataV = { "A", "B", "C" };
const std::array<std::string, 3> dataA = { "A", "B", "C" };
If I now modify these to only have two values.
// The vector will auto resize
const std::vector<std::string> dataV = { "A", "B"};
// This will still be of size three.
// This is not usually what you want.
const std::array<std::string, 3> dataA = { "A", "B"};
// The person modifying the code has to manually spot that and
// change the type to explicitly have two member array. Note
// It may not be as obvious as you think as the type may
// be hidden with a type alias of some description
using DataStore = std::array<std::string, 3>;
/// Lots of code:
DataStore dataA = { "A", "B"}; // Would you have spotted.
I have some code that uses a std::array. This is using the stack to allocate the memory. But I need to create an array of around 2MB. So doing some searching it seems that I can use std::vector that uses the heap.
I modified my code to do that
//alignas(128) std::array<uint32_t, array_size> write_data;
//alignas(128) std::array<uint32_t, array_size> read_data = { { 0 } };
alignas(128) std::vector<uint32_t> write_data[array_size];
alignas(128) std::vector<uint32_t> read_data[array_size];
But I am now getting error on other parts of the code. This uses some threads
std::thread read_thread(read, std::ref(dev),
(void*)read_data.data(), read_data.size() * sizeof(uint32_t), dma_block_size*32);
std::thread write_thread(write, std::ref(dev),
(void*)write_data.data(), write_data.size() * sizeof(uint32_t), num_dma_blocks);
E0289 no instance of constructor "std::thread::thread" matches the argument list
E0153 expression must have class type
The problem is on the read/write and read_data/write_data in the code above. Could someone tell me what the issue is as I am not really a cpp programmer. Thanks
You can init vector with a specific size using a constructor like this:
std::vector<int> vec(10);
By using std::vector<int> vec[10]; you declare array of 10 vectors. each vector is empty.
BTW: if you use std::vector<int> vec{10}; you declare a vector with a single int which is equal to 10.
It seems if I change the vector init to the below then it works
alignas(128) std::vector<uint32_t> write_data (array_size);
alignas(128) std::vector<uint32_t> read_data (array_size);
It seems to me that I should be able to use std::begin() and std::end() to convert ArrayXd to std::vector<double>; however, when I tried it in the following code, my attempt failed. My understanding is that .data() method on any Eigen object returns a pointer to a continuous block of memory similar to c style array. Therefore, since I can use std::begin(), std::end() on a c style array, I expected that to work with .data() as well. However, Eigen classes are templated, and I think this is what causes me problems, but don't see a way to fix this. How should this be done?
#include <iostream>
#include <vector>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
ArrayXd e_array(5);
e_array << 3,4,5,6,7;
double c_array[] = {1,2,3,4,5};
//Fails
// std::vector<double> my_vec(std::begin(e_array.data()), std::end(e_array.data()));
// Works
// std::vector<double> my_vec(e_array.data(), e_array.data() + 5);
// Works
// std::vector<double> my_vec(std::begin(c_array), std::end(c_array));
// Works
// std::vector<double> my_vec(c_array, c_array + 5);
return 0;
}
My error message(First lines, the whole message is long):
error: no matching function for call to
‘begin(Eigen::PlainObjectBase >::Scalar*)’
std::vector my_vec(std::begin(e_array.data()),
std::end(e_array.data()))
std::begin(vec.data()) cannot work because data() returns a raw pointer which cannot convey the number of elements in the vector. This version is the best one of yours:
std::vector<double> my_vec(e_array.data(), e_array.data() + 5);
And slightly better:
std::vector<double> my_vec(e_array.data(), e_array.data() + e_array.size());
And you may also be able to do this with many containers, but not with Eigen's ArrayXd in particular, because it lacks begin() and end() (related: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=231).
std::vector<double> my_vec(foo.begin(), foo.end());
I have a lot of C# Code that I have to write in C++. I don't have much experience in C++.
I am using Visual Studio 2012 to build. The project is an Static Library in C++ (not in C++/CLI).
I am sorry if this has been answered already, but I just couldn't find it.
In the C# code they would initialize a lot of arrays like this:
C#
double[] myArray = {10, 20, 30, 40};
Looking at how they were using arrays, when copying the code to C++ I decided to use std::vector to replace them. I would like to be able to initialize the vectors in the same way, because in the Unit Tests they use the arrays initialisation heavily, but I can't. I think in further versions of c++, vector supports it, but not in the one I have.
(Update)To make my previous statement more clear:
This doesn't work in VS2012:
vector<double> myVector{10, 20, 30, 40};
From this question I learned to create a vector from an array, so now I have a function like this:
C++
template<typename T, size_t N>
static std::vector<T> GetVectorFromArray( const T (&array)[N] )
{
return std::vector<T>(array, array+N);
}
It works great, but now that means I have to create the array and then use my function:
C++ (I would like to avoid this, since the UnitTests have many arrays.)
double array[] = {1, 3, 5};
vector<double> myVector = ArrayUtils::GetVectorFromArray(array);
Is there a way I could make my function GetVectorFromArray receive a list of items, that I could later convert into a vector?
My compiler doesn't support C++11
You can't have "literal" arrays except when initializing an array in a declaration.
At least that was the case before C++11 standard, which allows things like what you want, but with an std::initializer_list argument:
template<typename T>
static std::vector<T> GetVectorFromArray( std::initializer_list<T> list )
{
return std::vector<T>(list);
}
On the other hand, if your compiler support C++11 you can use it directly with the std::vector instead:
std::vector<int> myVector = { 1, 3, 5 };
Or even (with uniform initialization)
std::vector<int> myVector{ 1, 3, 5 };
Note: Unfortunately VS2012 doesn't support these things, so you either to use temporary arrays, or upgrade to a compiler which support it (like VS2013, or GCC, or Clang).
There are alternatives. One of them is the Boost assignment library (as answered by Mark Tolonen).
You can also use old C-style variable arguments. See e.g. this old question and its accepted answer for tips on how to do that. For this to work, you either need to provide the number of elements in the argument list as the first function argument, or provide a special sentinel to mark the end of the list. A warning though: As this is inherited straight from C, the extra type-safety provided by C++ doesn't exist. If you give an argument of the wrong type (say a double or a char) you might get undefined behavior.
The only other solution is to emulate e.g. the Boost assignment library, but that will require ridiculous amounts of code for such a simple thing.
You can simulate this behavior using the third-party C++ library, Boost:
#include <boost/assign.hpp>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);
for(auto i : v)
std::cout << i << std::endl;
}
You can also initialize a vector from an array using only the std library via non-member begin/end:
#include <boost/assign.hpp>
#include <vector>
#include <iostream>
int main()
{
int array[] = {1,2,3,4,5,6,7,8,9,10};
std::vector<int> v(std::begin(array),std::end(array));
for(auto i : v)
std::cout << i << std::endl;
}
Visual studio 2012 does not support initializer list. You could use VS 2013 for support (or g++)
Is there any problem with my code ?
std::vector<int[2]> weights;
int weight[2] = {1,2};
weights.push_back(weight);
It can't be compiled, please help to explain why:
no matching function for call to ‘std::vector<int [2], std::allocator<int [2]> >::push_back(int*&)’
The reason arrays cannot be used in STL containers is because it requires the type to be copy constructible and assignable (also move constructible in c++11). For example, you cannot do the following with arrays:
int a[10];
int b[10];
a = b; // Will not work!
Because arrays do not satisfy the requirements, they cannot be used. However, if you really need to use an array (which probably is not the case), you can add it as a member of a class like so:
struct A { int weight[2];};
std::vector<A> v;
However, it probably would be better if you used an std::vector or std::array.
You cant do that simply.
It's better you use either of these:
vector <vector<int>> (it's basically a two dimensional vector.It should work in your case)
vector< string > (string is an array of characters ,so you require a type cast later.It can be easily.).
you can declare an structure (say S) having array of int type within it i.e.
struct S{int a[num]} ,then declare vector of
vector< S>
So indirectly, you are pushing array into a vector.
Array can be added to container like this too.
int arr[] = {16,2,77,29};
std::vector<int> myvec (arr, arr + sizeof(arr) / sizeof(int) );
Hope this helps someone.
Arrays aren't copy constructable so you can't store them in containers (vector in this case). You can store a nested vector or in C++11 a std::array.
You should use std::array instead of simple array:
#include <vector>
#include <array>
std::vector<std::array<int, 2>> weights;
std::array<int, 2> weight = {1, 2};
weights.push_back(weight);
or with a constructor:
std::vector<std::array<int, 2>> weights;
weights.push_back(std::array<int, 2> ({1, 2});
One possible solution is:
std::vector<int*> weights;
int* weight = new int[2];
weight[0] =1; weight[1] =2;
weights.push_back(weight);
Just use
vector<int*> .That will definitely work.
A relevant discussion on the same topic : Pushing an array into a vector
Situation like:
int arr[3] = { 1, 2, 3 };
std::vector<int[]> v;
v.push_back(arr);
doesn't work with error "cannot initialize array in vector with .."
This, could be worked well
int * arr = new int[3] { 1, 2, 3 };
std::vector<int*> v;
v.push_back(arr);
To instantiate the vector, you need to supply a type, but int[2] is not a type, it's a declaration.