Pass array through class constructor using C++ variadic templates - c++

I would like to modernize a small mathematical library using new C++ paradigms (I have a C++17 compiler). In specific, I need to pass an array to a class through constructor.
This is the "classical" old way I used. It works
class Vector {
public:
long double* elements;
public:
Vector(int size, long double *array) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(10, array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
So, I tried to change Vector class with what I have understood about variadic templates and parameter pack. It doesn't work
class Vector {
public:
long double* elements;
public:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{args...};
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
The error returned by compiler is
error: cannot convert ‘long double*’ to ‘long double’ in initialization
elements = new long double[size]{args...};
What am I doing wrong?
Further, I'm wondering if it is possible to use a std::array instead of raw array, both either inside main method and in Vector class.

To pass an array like that variadic templates are not the solution. Variadic templates are used to pass N numbers of parameters to a class/function. Yet you are passing only one parameter!
I would suggest you to
I suggest you tu use array references, which are available in all C++ versions:
class Vector {
public:
long double* elements;
public:
template<std::size_t size>
Vector(long double (&array)[size]) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
By the way, if you can, use vector. I highly doubt this custom vector class is as efficient as std::vector (no geometric growth or optimized copy and move)

I'm not sure if this answers your question, but I would give you a general advice:
I guess you want to encapsulate your own logic into the vector.
The standard library vector is very advanced and you should use it, instead of loosing time to write your own low-level code. You could concentrate more on the logic you need.
Your could define your own vector and still use the advantages of the std::vector for constructing your Vector objects.
For example with inheritance:
template<typename T>
class Vector : public std::vector<int>
{
// here comes the implementation of your interface.
}
or composition:
template<typename T>
class Vector {
private:
std::vector<T> elems;
}
In the case of composition you'd have to define the constructors you need.
In both cases you could then use your own Vector as follows:
Vector<double> vec1(10); // construct vector with 10 double's each = 0
Vector<double> vec2(10, 5); // construct vector with 10 double's each = 5
Vector<double> vec3{1,2,3,4}; // using initializer list
Vector<double> vec4(somecontainer.begin(), somecontainer.end()); // construct vector by copying elemts from some other container
etc.
As you see with std::vector you'are getting all the benefits you need for constructing your own Vector object.

According to your definition of
template<typename... Args> Vector(Args... args);
You want to use this constructor in this way:
Vector vector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
It is possible, if you sightly modify your definition of the constructor to:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{static_cast<long double>(args)...};
}
Please note such kind of use is not good practice, you should normally use std containers and avoid new operator.

Related

how to save vector from c++ to c [duplicate]

How do I convert a std::vector<double> to a double 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];
What for? You need to clarify: Do you need a pointer to the first element of an array, or an array?
If you're calling an API function that expects the former, you can do do_something(&v[0], v.size()), where v is a vector of doubles. The elements of a vector are contiguous.
Otherwise, you just have to copy each element:
double arr[100];
std::copy(v.begin(), v.end(), arr);
Ensure not only thar arr is big enough, but that arr gets filled up, or you have uninitialized values.
For C++11, vector.data() will do the trick.
vector<double> thevector;
//...
double *thearray = &thevector[0];
This is guaranteed to work by the standard, however there are some caveats: in particular take care to only use thearray while thevector is in scope.
As to std::vector<int> vec, vec to get int*, you can use two method:
int* arr = &vec[0];
int* arr = vec.data();
If you want to convert any type T vector to T* array, just replace the above int to T.
I will show you why does the above two works, for good understanding?
std::vector is a dynamic array essentially.
Main data member as below:
template <class T, class Alloc = allocator<T>>
class vector{
public:
typedef T value_type;
typedef T* iterator;
typedef T* pointer;
//.......
private:
pointer start_;
pointer finish_;
pointer end_of_storage_;
public:
vector():start_(0), finish_(0), end_of_storage_(0){}
//......
}
The range (start_, end_of_storage_) is all the array memory the vector allocate;
The range(start_, finish_) is all the array memory the vector used;
The range(finish_, end_of_storage_) is the backup array memory.
For example, as to a vector vec. which has {9, 9, 1, 2, 3, 4} is pointer may like the below.
So &vec[0] = start_ (address.) (start_ is equivalent to int* array head)
In c++11 the data() member function just return start_
pointer data()
{
return start_; //(equivalent to `value_type*`, array head)
}
Vectors effectively are arrays under the skin. If you have a function:
void f( double a[]);
you can call it like this:
vector <double> v;
v.push_back( 1.23 )
f( &v[0] );
You should not ever need to convert a vector into an actual array instance.
std::vector<double> vec;
double* arr = vec.data();
We can do this using data() method. C++11 provides this method.
Code Snippet
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
vector<int>v = {7, 8, 9, 10, 11};
int *arr = v.data();
for(int i=0; i<v.size(); i++)
{
cout<<arr[i]<<" ";
}
return 0;
}
If you have a function, then you probably need this:foo(&array[0], array.size());. If you managed to get into a situation where you need an array then you need to refactor, vectors are basically extended arrays, you should always use them.
You can do some what like this
vector <int> id;
vector <double> v;
if(id.size() > 0)
{
for(int i = 0; i < id.size(); i++)
{
for(int j = 0; j < id.size(); j++)
{
double x = v[i][j];
cout << x << endl;
}
}
}

How to convert vector to array

How do I convert a std::vector<double> to a double 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];
What for? You need to clarify: Do you need a pointer to the first element of an array, or an array?
If you're calling an API function that expects the former, you can do do_something(&v[0], v.size()), where v is a vector of doubles. The elements of a vector are contiguous.
Otherwise, you just have to copy each element:
double arr[100];
std::copy(v.begin(), v.end(), arr);
Ensure not only thar arr is big enough, but that arr gets filled up, or you have uninitialized values.
For C++11, vector.data() will do the trick.
vector<double> thevector;
//...
double *thearray = &thevector[0];
This is guaranteed to work by the standard, however there are some caveats: in particular take care to only use thearray while thevector is in scope.
As to std::vector<int> vec, vec to get int*, you can use two method:
int* arr = &vec[0];
int* arr = vec.data();
If you want to convert any type T vector to T* array, just replace the above int to T.
I will show you why does the above two works, for good understanding?
std::vector is a dynamic array essentially.
Main data member as below:
template <class T, class Alloc = allocator<T>>
class vector{
public:
typedef T value_type;
typedef T* iterator;
typedef T* pointer;
//.......
private:
pointer start_;
pointer finish_;
pointer end_of_storage_;
public:
vector():start_(0), finish_(0), end_of_storage_(0){}
//......
}
The range (start_, end_of_storage_) is all the array memory the vector allocate;
The range(start_, finish_) is all the array memory the vector used;
The range(finish_, end_of_storage_) is the backup array memory.
For example, as to a vector vec. which has {9, 9, 1, 2, 3, 4} is pointer may like the below.
So &vec[0] = start_ (address.) (start_ is equivalent to int* array head)
In c++11 the data() member function just return start_
pointer data()
{
return start_; //(equivalent to `value_type*`, array head)
}
Vectors effectively are arrays under the skin. If you have a function:
void f( double a[]);
you can call it like this:
vector <double> v;
v.push_back( 1.23 )
f( &v[0] );
You should not ever need to convert a vector into an actual array instance.
std::vector<double> vec;
double* arr = vec.data();
We can do this using data() method. C++11 provides this method.
Code Snippet
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
vector<int>v = {7, 8, 9, 10, 11};
int *arr = v.data();
for(int i=0; i<v.size(); i++)
{
cout<<arr[i]<<" ";
}
return 0;
}
If you have a function, then you probably need this:foo(&array[0], array.size());. If you managed to get into a situation where you need an array then you need to refactor, vectors are basically extended arrays, you should always use them.
You can do some what like this
vector <int> id;
vector <double> v;
if(id.size() > 0)
{
for(int i = 0; i < id.size(); i++)
{
for(int j = 0; j < id.size(); j++)
{
double x = v[i][j];
cout << x << endl;
}
}
}

creating an array which can hold objects of different classes in C++

How can I create an array which can hold objects of different classes in C++?
You can use boost::any or boost::variant (comparing between the two: [1]).
Alternatively, if the "objects of different classes" have a common ancestor (say, Base), you could use a std::vector<Base*> (or std::vector<std::tr1::shared_ptr<Base> >), and cast the result to Derived* when you need it.
define an base class and derive all your classes from this.
Then you could create a list of type(base*) and it could contain any object of Base type or derived type
Have a look at boost::fusion which is an stl-replica, but with the ability to store different data types in containers
If you want to create your own, wrap access to a pointer/array using templates and operator overloading. Below is a small example:
#include <iostream>
using namespace std;
template <class T>
class Array
{
private:
T* things;
public:
Array(T* a, int n) {
things = new T[n];
for (int i=0; i<n; i++) {
things[i] = a[i];
}
}
~Array() {
delete[] things;
}
T& operator [](const int idx) const {
return things[idx];
}
};
int main()
{
int a[] = {1,2,3};
double b[] = {1.2, 3.5, 6.0};
Array<int> intArray(a, 3);
Array<double> doubleArray(b, 3);
cout << "intArray[1]: " << intArray[1] << endl;
}

What is the easiest way to initialize a std::vector with hardcoded elements?

I can create an array and initialize it like this:
int a[] = {10, 20, 30};
How do I create a std::vector and initialize it similarly elegant?
The best way I know is:
std::vector<int> ints;
ints.push_back(10);
ints.push_back(20);
ints.push_back(30);
Is there a better way?
If your compiler supports C++11, you can simply do:
std::vector<int> v = {1, 2, 3, 4};
This is available in GCC as of version 4.4. Unfortunately, VC++ 2010 seems to be lagging behind in this respect.
Alternatively, the Boost.Assign library uses non-macro magic to allow the following:
#include <boost/assign/list_of.hpp>
...
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);
Or:
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
...
std::vector<int> v;
v += 1, 2, 3, 4;
But keep in mind that this has some overhead (basically, list_of constructs a std::deque under the hood) so for performance-critical code you'd be better off doing as Yacoby says.
One method would be to use the array to initialize the vector
static const int arr[] = {16,2,77,29};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
If you can, use the modern C++[11,14,17,20,...] way:
std::vector<int> ints = {10, 20, 30};
The old way of looping over a variable-length array or using sizeof() is truly terrible on the eyes and completely unnecessary in terms of mental overhead. Yuck.
In C++0x you will be able to do it in the same way that you did with an array, but not in the current standard.
With only language support you can use:
int tmp[] = { 10, 20, 30 };
std::vector<int> v( tmp, tmp+3 ); // use some utility to avoid hardcoding the size here
If you can add other libraries you could try boost::assignment:
vector<int> v = list_of(10)(20)(30);
To avoid hardcoding the size of an array:
// option 1, typesafe, not a compile time constant
template <typename T, std::size_t N>
inline std::size_t size_of_array( T (&)[N] ) {
return N;
}
// option 2, not typesafe, compile time constant
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
// option 3, typesafe, compile time constant
template <typename T, std::size_t N>
char (&sizeof_array( T(&)[N] ))[N]; // declared, undefined
#define ARRAY_SIZE(x) sizeof(sizeof_array(x))
In C++11:
#include <vector>
using std::vector;
...
vector<int> vec1 { 10, 20, 30 };
// or
vector<int> vec2 = { 10, 20, 30 };
Using Boost list_of:
#include <vector>
#include <boost/assign/list_of.hpp>
using std::vector;
...
vector<int> vec = boost::assign::list_of(10)(20)(30);
Using Boost assign:
#include <vector>
#include <boost/assign/std/vector.hpp>
using std::vector;
...
vector<int> vec;
vec += 10, 20, 30;
Conventional STL:
#include <vector>
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
Conventional STL with generic macros:
#include <vector>
#define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0])
#define ARRAY_END(ar) (ar + ARRAY_SIZE(ar))
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec (arr, ARRAY_END(arr));
Conventional STL with a vector initializer macro:
#include <vector>
#define INIT_FROM_ARRAY(ar) (ar, ar + sizeof(ar) / sizeof(ar[0])
using std::vector;
...
static const int arr[] = {10,20,30};
vector<int> vec INIT_FROM_ARRAY(arr);
I tend to declare
template< typename T, size_t N >
std::vector<T> makeVector( const T (&data)[N] )
{
return std::vector<T>(data, data+N);
}
in a utility header somewhere and then all that's required is:
const double values[] = { 2.0, 1.0, 42.0, -7 };
std::vector<double> array = makeVector(values);
Before C++ 11:
Method 1
vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
Method 2
vector<int>v;
v.push_back(SomeValue);
C++ 11 onward below is also possible
vector<int>v = {1, 3, 5, 7};
We can do this as well
vector<int>v {1, 3, 5, 7}; // Notice .. no "=" sign
For C++ 17 onwards we can omit the type
vector v = {1, 3, 5, 7};
Starting with:
int a[] = {10, 20, 30}; //I'm assuming 'a' is just a placeholder
If you don't have a C++11 compiler and you don't want to use Boost:
const int a[] = {10, 20, 30};
const std::vector<int> ints(a, a+sizeof(a)/sizeof(int)); //Make it const if you can
If you don't have a C++11 compiler and can use Boost:
#include <boost/assign.hpp>
const std::vector<int> ints = boost::assign::list_of(10)(20)(30);
If you do have a C++11 compiler:
const std::vector<int> ints = {10,20,30};
For vector initialisation -
vector<int> v = {10, 20, 30}
can be done if you have a C++11 compiler.
Else, you can have an array of the data and then use a for loop.
int array[] = {10,20,30}
for(unsigned int i=0; i<sizeof(array)/sizeof(array[0]); i++)
{
v.push_back(array[i]);
}
Apart from these, there are various other ways described in previous answers using some code. In my opinion, these ways are easy to remember and quick to write.
The easiest way to do it is:
vector<int> ints = {10, 20, 30};
If your compiler supports Variadic macros (which is true for most modern compilers), then you can use the following macro to turn vector initialization into a one-liner:
#define INIT_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))
With this macro, you can define an initialized vector with code like this:
INIT_VECTOR(int, my_vector, {1, 2, 3, 4});
This would create a new vector of ints named my_vector with the elements 1, 2, 3, 4.
I build my own solution using va_arg. This solution is C++98 compliant.
#include <cstdarg>
#include <iostream>
#include <vector>
template <typename T>
std::vector<T> initVector (int len, ...)
{
std::vector<T> v;
va_list vl;
va_start(vl, len);
for (int i = 0; i < len; ++i)
v.push_back(va_arg(vl, T));
va_end(vl);
return v;
}
int main ()
{
std::vector<int> v = initVector<int> (7,702,422,631,834,892,104,772);
for (std::vector<int>::const_iterator it = v.begin() ; it != v.end(); ++it)
std::cout << *it << std::endl;
return 0;
}
Demo
If you don't want to use Boost, but want to enjoy syntax like
std::vector<int> v;
v+=1,2,3,4,5;
just include this chunk of code
template <class T> class vector_inserter{
public:
std::vector<T>& v;
vector_inserter(std::vector<T>& v):v(v){}
vector_inserter& operator,(const T& val){v.push_back(val);return *this;}
};
template <class T> vector_inserter<T> operator+=(std::vector<T>& v,const T& x){
return vector_inserter<T>(v),x;
}
In C++11:
static const int a[] = {10, 20, 30};
vector<int> vec (begin(a), end(a));
A more recent duplicate question has this answer by Viktor Sehr. For me, it is compact, visually appealing (looks like you are 'shoving' the values in), doesn't require C++11 or a third-party module, and avoids using an extra (written) variable. Below is how I am using it with a few changes. I may switch to extending the function of vector and/or va_arg in the future instead.
// Based on answer by "Viktor Sehr" on Stack Overflow
// https://stackoverflow.com/a/8907356
//
template <typename T>
class mkvec {
public:
typedef mkvec<T> my_type;
my_type& operator<< (const T& val) {
data_.push_back(val);
return *this;
}
my_type& operator<< (const std::vector<T>& inVector) {
this->data_.reserve(this->data_.size() + inVector.size());
this->data_.insert(this->data_.end(), inVector.begin(), inVector.end());
return *this;
}
operator std::vector<T>() const {
return data_;
}
private:
std::vector<T> data_;
};
std::vector<int32_t> vec1;
std::vector<int32_t> vec2;
vec1 = mkvec<int32_t>() << 5 << 8 << 19 << 79;
// vec1 = (5, 8, 19, 79)
vec2 = mkvec<int32_t>() << 1 << 2 << 3 << vec1 << 10 << 11 << 12;
// vec2 = (1, 2, 3, 5, 8, 19, 79, 10, 11, 12)
You can do that using boost::assign:
vector<int> values;
values += 1,2,3,4,5,6,7,8,9;
Details are here.
The below methods can be used to initialize the vector in C++.
int arr[] = {1, 3, 5, 6}; vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
vector<int>v; v.push_back(1); v.push_back(2); v.push_back(3); and so on
vector<int>v = {1, 3, 5, 7};
The third one is allowed only in C++11 onwards.
There are a lot of good answers here, but since I independently arrived at my own before reading this, I figured I'd toss mine up here anyway...
Here's a method that I'm using for this which will work universally across compilers and platforms:
Create a struct or class as a container for your collection of objects. Define an operator overload function for <<.
class MyObject;
struct MyObjectList
{
std::list<MyObject> objects;
MyObjectList& operator<<( const MyObject o )
{
objects.push_back( o );
return *this;
}
};
You can create functions which take your struct as a parameter, e.g.:
someFunc( MyObjectList &objects );
Then, you can call that function, like this:
someFunc( MyObjectList() << MyObject(1) << MyObject(2) << MyObject(3) );
That way, you can build and pass a dynamically sized collection of objects to a function in one single clean line!
If you want something on the same general order as Boost::assign without creating a dependency on Boost, the following is at least vaguely similar:
template<class T>
class make_vector {
std::vector<T> data;
public:
make_vector(T const &val) {
data.push_back(val);
}
make_vector<T> &operator,(T const &t) {
data.push_back(t);
return *this;
}
operator std::vector<T>() { return data; }
};
template<class T>
make_vector<T> makeVect(T const &t) {
return make_vector<T>(t);
}
While I wish the syntax for using it was cleaner, it's still not particularly awful:
std::vector<int> x = (makeVect(1), 2, 3, 4);
typedef std::vector<int> arr;
arr a {10, 20, 30}; // This would be how you initialize while defining
To compile use:
clang++ -std=c++11 -stdlib=libc++ <filename.cpp>
// Before C++11
// I used following methods:
// 1.
int A[] = {10, 20, 30}; // original array A
unsigned sizeOfA = sizeof(A)/sizeof(A[0]); // calculate the number of elements
// declare vector vArrayA,
std::vector<int> vArrayA(sizeOfA); // make room for all
// array A integers
// and initialize them to 0
for(unsigned i=0; i<sizeOfA; i++)
vArrayA[i] = A[i]; // initialize vector vArrayA
//2.
int B[] = {40, 50, 60, 70}; // original array B
std::vector<int> vArrayB; // declare vector vArrayB
for (unsigned i=0; i<sizeof(B)/sizeof(B[0]); i++)
vArrayB.push_back(B[i]); // initialize vArrayB
//3.
int C[] = {1, 2, 3, 4}; // original array C
std::vector<int> vArrayC; // create an empty vector vArrayC
vArrayC.resize(sizeof(C)/sizeof(C[0])); // enlarging the number of
// contained elements
for (unsigned i=0; i<sizeof(C)/sizeof(C[0]); i++)
vArrayC.at(i) = C[i]; // initialize vArrayC
// A Note:
// Above methods will work well for complex arrays
// with structures as its elements.
It is pretty convenient to create a vector inline without defining variable when writing test, for example:
assert(MyFunction() == std::vector<int>{1, 3, 4}); // <- this.
"How do I create an STL vector and initialize it like the above? What is the best way to do so with the minimum typing effort?"
The easiest way to initialize a vector as you've initialized your built-in array is using an initializer list which was introduced in C++11.
// Initializing a vector that holds 2 elements of type int.
Initializing:
std::vector<int> ivec = {10, 20};
// The push_back function is more of a form of assignment with the exception of course
//that it doesn't obliterate the value of the object it's being called on.
Assigning
ivec.push_back(30);
ivec is 3 elements in size after Assigning (labeled statement) is executed.
There are various ways to hardcode a vector. I will share few ways:
Initializing by pushing values one by one
// Create an empty vector
vector<int> vect;
vect.push_back(10);
vect.push_back(20);
vect.push_back(30);
Initializing like arrays
vector<int> vect{ 10, 20, 30 };
Initializing from an array
int arr[] = { 10, 20, 30 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> vect(arr, arr + n);
Initializing from another vector
vector<int> vect1{ 10, 20, 30 };
vector<int> vect2(vect1.begin(), vect1.end());
If the array is:
int arr[] = {1, 2, 3};
int len = (sizeof(arr)/sizeof(arr[0])); // finding length of array
vector < int > v;
v.assign(arr, arr+len); // assigning elements from array to vector
Related, you can use the following if you want to have a vector completely ready to go in a quick statement (e.g. immediately passing to another function):
#define VECTOR(first,...) \
([](){ \
static const decltype(first) arr[] = { first,__VA_ARGS__ }; \
std::vector<decltype(first)> ret(arr, arr + sizeof(arr) / sizeof(*arr)); \
return ret;})()
example function
template<typename T>
void test(std::vector<T>& values)
{
for(T value : values)
std::cout<<value<<std::endl;
}
example use
test(VECTOR(1.2f,2,3,4,5,6));
though be careful about the decltype, make sure the first value is clearly what you want.
B. Stroustrup describes a nice way to chain operations in 16.2.10 Selfreference on page 464 in the C++11 edition of the Prog. Lang. where a function returns a reference, here modified to a vector. This way you can chain like v.pb(1).pb(2).pb(3); but may be too much work for such small gains.
#include <iostream>
#include <vector>
template<typename T>
class chain
{
private:
std::vector<T> _v;
public:
chain& pb(T a) {
_v.push_back(a);
return *this;
};
std::vector<T> get() { return _v; };
};
using namespace std;
int main(int argc, char const *argv[])
{
chain<int> v{};
v.pb(1).pb(2).pb(3);
for (auto& i : v.get()) {
cout << i << endl;
}
return 0;
}
1
2
3
The simplest, ergonomic way (with C++ 11 or later):
auto my_ints = {1,2,3};
In case you want to have it in your own class:
#include <initializer_list>
Vector<Type>::Vector(std::initializer_list<Type> init_list) : _size(init_list.size()),
_capacity(_size),
_data(new Type[_size])
{
int idx = 0;
for (auto it = init_list.begin(); it != init_list.end(); ++it)
_data[idx++] = *it;
}

Initializing a ublas vector from a C array

I am writing a Matlab extension using the C++ ublas library, and I would like to be able to initialize my ublas vectors from the C arrays passed by the Matlab interpeter.
How can I initialize the ublas vector from a C array without (for the sake of efficiency) explicitly copying the data. I am looking for something along the following lines of code:
using namespace boost::numeric::ublas;
int pv[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
vector<int> v (pv);
In general, is it possible to initialize a C++ std::vector from an array? Something like this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int pv[4] = { 4, 4, 4, 4};
vector<int> v (pv, pv+4);
pv[0] = 0;
cout << "v[0]=" << v[0] << " " << "pv[0]=" << pv[0] << endl;
return 0;
}
but where the initialization would not copy the data. In this case the output is
v[0]=4 pv[0]=0
but I want the output to be the same, where updating the C array changes the data pointed to by the C++ vector
v[0]=0 pv[0]=0
I'm not sure how your question relates to MATLAB/MEX, but a side note, you might want to know that MATLAB implements a copy-on-write strategy.
This means that when you copy an array for example, only some headers are actually copied, while the data itself is shared between the two arrays. And once one of them is modified, a copy of the data is actually made.
The following is a simluation of what might be happening under the hood (borrowed from this old post):
-----------------------------------------
>> a = [35.7 100.2 1.2e7];
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink=0
-----------------------------------------
>> b = a;
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink / \
| / \ |
| | |
| | |
\ / | |
crosslink |
mxArray b |
pdata --------
-----------------------------------------
>> a(1) = 1;
mxArray a
pdata -----> (1) 100.2 1.2e7
crosslink=0
crosslink=0
mxArray b
pdata ------> 35.7 100.2 1.2e7 ...
I know this doesn't really answer your question, I just thought you might find the concept helpful.
Both std::vector and ublas::vector are containers. The whole point of containers is to manage the storage and lifetimes of their contained objects. This is why when you initialize them they must copy values into storage that they own.
C arrays are areas of memory fixed in size and location so by their nature you can only get their values into a container by copying.
You can use C arrays as the input to many algorithm functions so perhaps you can do that to avoid the initial copy?
You can initialize a std::vector from a C array easily:
vector<int> v(pv, pv+10);
There are two undocumented classes in uBLAS storage.hpp. You can change the default storage class (unbounded_array) in ublas::vector with one of these.
The first class, array_adaptor, makes a copy of your data when ublas::vector calls to copy constructor, not very useful class at all. I would rather simply the appropriate constructor to do this in unbounded_array or bounded_array classes.
The second, shallow_array_adaptor, only hold a reference of your data, so you can use vector to directly modify your C array. Unfortunately, it has some bugs, when you assign an expression it losses the original data pointer. But you can create a derived class that fix this problem.
Here the patch and an example:
// BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR must be defined before include vector.hpp
#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR
#include <boost/numeric/ublas/vector.hpp>
#include <algorithm>
#include <iostream>
// Derived class that fix base class bug. Same name, different namespace.
template<typename T>
class shallow_array_adaptor
: public boost::numeric::ublas::shallow_array_adaptor<T>
{
public:
typedef boost::numeric::ublas::shallow_array_adaptor<T> base_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::pointer pointer;
shallow_array_adaptor(size_type n) : base_type(n) {}
shallow_array_adaptor(size_type n, pointer data) : base_type(n,data) {}
shallow_array_adaptor(const shallow_array_adaptor& c) : base_type(c) {}
// This function must swap the values ​​of the items, not the data pointers.
void swap(shallow_array_adaptor& a) {
if (base_type::begin() != a.begin())
std::swap_ranges(base_type::begin(), base_type::end(), a.begin());
}
};
void test() {
using namespace boost::numeric;
typedef ublas::vector<double,shallow_array_adaptor<double> > vector_adaptor;
struct point {
double x;
double y;
double z;
};
point p = { 1, 2, 3 };
vector_adaptor v(shallow_array_adaptor<double>(3, &p.x));
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
v += v*2.0;
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
}
Output:
1 2 3
3 6 9
The usual suggestion to use shallow array adaptor seems kind of sarcastic to me - to be able to simply access an array through a pointer you're supposed to put it into a shared_array with all the reference counting shebang (that comes to nothing, since you don't own the array) and what's more with a nightmare of data-aliasing.
Actually, uBLAS has a fully-fledged implementation of storage (array_adaptor) which allows to use vectors with external c arrays. The only catch is vector constructor which makes a copy. Why this nice feature is not used in the library is quite beyond me, but anyway, we can use a little extension (it's actually 2 lines of code surrounded with usual c++ bloat)
template<class T>
class extarray_vector :
public vector<T, array_adaptor<T> >
{
typedef vector<T, array_adaptor<T> > vector_type;
public:
BOOST_UBLAS_INLINE
extarray_vector(size_type size, pointer p)
{ data().resize(size, p); }
template <size_type N>
BOOST_UBLAS_INLINE
extarray_vector(T (&a)[N])
{ data().resize(N, a); }
template<class V>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector<T, V>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VC>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_container<VC>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VE>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_expression<VE>& ae)
{
vector_type::operator = (ae);
return *this;
}
};
you can use it like this:
int i[] = {1, 4, 9, 16, 25, 36, 49};
extarray_vector<int> iv(i);
BOOST_ASSERT_MSG(i == &iv[0], "Vector should attach to external array\n");
iv[3] = 100;
BOOST_ASSERT(i[3] == 100);
iv.resize(iv.size() + 1, true);
BOOST_ASSERT_MSG(i != &iv[0], "And detach from the array on resize\n");
iv[3] = 200;
BOOST_ASSERT(i[3] == 100);
iv.data().resize(7, i, 0);
BOOST_ASSERT_MSG(i == &iv[0], "And attach back to the array\n");
BOOST_ASSERT(i[3] == 200);
You can dynamically attach and detach vector to external storage via array_adaptor's resize method (keeping or discarding data). On resize it detaches from storage automatically and becomes regular vector. Assignment from containers goes directly into storage, but assignment from expression is done via a temporary and vector is detached from storage, use noalias() to prevent that. There's a small overhead in constructor since data_ is private member and we have to default initialize it with new T[0], then reassign to external array. You may change it to protected and assign to storage directly in the constructor.
Here are a couple of functions for syntactically convenient assignment (admittedly not initialization):
vector<int> v;
setVector(v, 3,
1, 2, 3);
matrix<int> m;
setMatrix(m, 3, 4,
1, 2, 3, 4,
11, 22, 33, 44,
111, 222, 333, 444);
The functions:
/**
* Resize a ublas vector and set its elements
*/
template <class T> void setVector(vector<T> &v, int n, ...)
{
va_list ap;
va_start(ap, n);
v.resize(n);
for (int i = 0; i < n; i++) {
v[i] = va_arg(ap, T);
}
va_end(ap);
}
/**
* Resize a ublas matrix and set its elements
*/
template <class T> void setMatrix(matrix<T> &m, int rows, int cols ...)
{
va_list ap;
va_start(ap, cols);
m.resize(rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m(i, j) = va_arg(ap, T);
}
}
va_end(ap);
}