How to initialize std::vector from C-style array? - c++

What is the cheapest way to initialize a std::vector from a C-style array?
Example: In the following class, I have a vector, but due to outside restrictions, the data will be passed in as C-style array:
class Foo {
std::vector<double> w_;
public:
void set_data(double* w, int len){
// how to cheaply initialize the std::vector?
}
Obviously, I can call w_.resize() and then loop over the elements, or call std::copy(). Are there any better methods?

Don't forget that you can treat pointers as iterators:
w_.assign(w, w + len);

You use the word initialize so it's unclear if this is one-time assignment or can happen multiple times.
If you just need a one time initialization, you can put it in the constructor and use the two iterator vector constructor:
Foo::Foo(double* w, int len) : w_(w, w + len) { }
Otherwise use assign as previously suggested:
void set_data(double* w, int len)
{
w_.assign(w, w + len);
}

Well, Pavel was close, but there's even a more simple and elegant solution to initialize a sequential container from a c style array.
In your case:
w_ (array, std::end(array))
array will get us a pointer to the beginning of the array (didn't catch it's name),
std::end(array) will get us an iterator to the end of the array.

The quick generic answer:
std::vector<double> vec(carray,carray+carray_size);
or question specific:
std::vector<double> w_(w,w+len);
based on above: Don't forget that you can treat pointers as iterators

You can 'learn' the size of the array automatically:
template<typename T, size_t N>
void set_data(const T (&w)[N]){
w_.assign(w, w+N);
}
Hopefully, you can change the interface to set_data as above. It still accepts a C-style array as its first argument. It just happens to take it by reference.
How it works
[ Update: See here for a more comprehensive discussion on learning the size ]
Here is a more general solution:
template<typename T, size_t N>
void copy_from_array(vector<T> &target_vector, const T (&source_array)[N]) {
target_vector.assign(source_array, source_array+N);
}
This works because the array is being passed as a reference-to-an-array. In C/C++, you cannot pass an array as a function, instead it will decay to a pointer and you lose the size. But in C++, you can pass a reference to the array.
Passing an array by reference requires the types to match up exactly. The size of an array is part of its type. This means we can use the template parameter N to learn the size for us.
It might be even simpler to have this function which returns a vector. With appropriate compiler optimizations in effect, this should be faster than it looks.
template<typename T, size_t N>
vector<T> convert_array_to_vector(const T (&source_array)[N]) {
return vector<T>(source_array, source_array+N);
}

std::vector<double>::assign is the way to go, because it's little code. But how does it work, actually? Doesnt't it resize and then copy? In MS implementation of STL I am using it does exactly so.
I'm afraid there's no faster way to implement (re)initializing your std::vector.

Related

Is there an advantage by passing std::array on the stack for API call

I was reading about the key differences between std::array and C type array and came to know that one of the key differences is that C type array when called to an API go as a pointer while a copy of std::array gets passed. One of the blogs mentioned that as an advantage but I don't think so. What are the key advantages of using an std::array over C-type array? My exploration and understanding suggests that almost everything can be done with C type arrays. They can even be passed to STL algorithms. So I don't see any key advantage of using std::array over C-type array. Is that actually so?
It's true that everything you can do with std::array could be done with C array. Actually, std::array simply wraps a fixed size C array internally. However, std::array is often more convenient.
Ability to pass an array by value is an advantage. If you'd like to do this with C array, you'd have to pass a pointer and size and then create local copy. With std::array, you can avoid this, and choose what better suits your needs:
void takeArrayByValue(std::array<int, 5> arr)
{
arr[0] = newValue; // arr is a local copy, caller does not see this
}
void takeArrayByReference(std::array<int, 5>& arr)
{
arr[0] = newValue; // variable passed as argument is modified
}
// compare with this:
void takeCArrayAndMakeLocalCopy(const int (&arr)[5])
{
int localArr[5];
std::copy(std::begin(arr), std::end(arr), localArr);
// do something with localArr
}
Another thing: it's easier to misuse C arrays:
void takeCAray(int arr[5]);
int arr[3];
takeCArray(arr); // compiles
In this example, takeCArray really takes a pointer. It should have been takeCArray(int (&arr)[5]), but compiler won't complain about this, and the bug can potentially stay unnoticed at first. This can't happen with std::array:
void takeStdArray(std::array<int, 5>& arr);
std::array<int, 3> arr;
takeStdArray(arr); // compiler error!

Convert const float* to std::array<float, ...>

I have a const float* pointing to a huge array, and would like to be able to access the elements through a std::array.
What is the best way to do this? Without copying the elements if possible.
Thanks!
In order to use std::array, you need to know the size of the array at compile time. You create an empty array and use std::copy to copy the elements into the array.
If the code which uses your const float* only knows that size at runtime, then you cannot use std::array but have to use std::vector. std::vector has a constructor to which you can pass pointers to the begin and end of the range to copy into it.
Note that in both cases, the container owns a copy of the original elements.
Without copying the elements if possible.
No, that is not possible. C++ standard containers are designed to own their contents, not just representing a view into them.
Here is an example to illustrate the difference:
#define SIZE 10 // let's assume some C or legacy code which uses macros
// ...
void f(const float* arr)
{
// size is known at compile time
std::array<float, SIZE> a;
std::copy(arr, arr + SIZE, begin(a));
}
void g(const float* arr, int size)
{
// size is only known at runtime
std::vector<float> v(arr, arr + size);
}
There are at least two proposed additions to the standard library that do something like that. One is std::experimental::to_array<T,N>(), which makes a deep copy of the entire data. That’s wasteful in terms of both time and memory, but could be useful if you really do want to create a copy, especially a const copy which you cannot create and then modify.
If what you want is a container interface to a range of data represented by an arbitrary pointer and element count, the Guideline Support Library offers a span template. I recommend that, if you pass both, you wrap them in a lightweight object similar to this.
Since you said you can change the interface to the constructor, I strongly suggest you do so. If you want to keep around the version that takes a std::array, you can, and delegate it to the version that takes an arbitrary range of data, such as:
#include <algorithm>
#include <array>
#include <iterator>
#include "span"
MyClass::MyClass( const span<value_type>& s /*, more, params */ )
{
/* In this example, m_storage is some private container and span has a
* container interface.
*/
auto it = std::back_inserter(m_storage);
std::copy_n( s.begin(), s.size(), it );
// ...
}
MyClass::MyClass( std::array<value_type, initializer_size>& a /*, more, params */ )
: MyClass( span<value_type>( a.data(), a.size() ) /*, more, params */ )
{}
std::array does not take ownership of pointers. You have to copy the elements. Use std::copy. It works on abstract iterators, for which pointers also qualify.
const float *source = ...; // C array of at least of size N
std::array<float, N> destination;
std::copy(source, source + N, destination.begin());
An aside: without copying the elements, the element type of whatever container with support for taking ownership of a pointer would have to be const float as well. Or you would have to use const_cast<> in case you were sure that the pointer is actually not really to const float. Please, only use const_cast<> in cases where it's absolutely unavoidable due to a flaw in an external API though :)

Passing the pointer to the first element of a vector if any

I have a function taking double*
void funct(double*);
and I have a vector:
std::vector<double> myVec;
how should I correctly and safely call funct(myVec)?
not safe:
funct(&myVec[0]);
funct(&*myVec.begin());
not nice to be read:
funct( myVec.empty()? NULL : &myVec[0]);
funct( myVec.empty()? NULL : &*myVec.begin());
any suggestion?
What's the standard approach?
Well, the standard class type std::vector has a member function called data, that is supposed to return the pointer to the underlying storage. Apparently data() is nothing more than &front() with the guaranteed that:
The pointer is such that range [data(); data() + size()) is always a valid range, even if the container is empty.
Therefore I'd say that both:
funct(vector.data());
funct(&vector.front());
can be safely used.
But the real question is: what are you trying to do inside the function?
I can see 3 obvious answers to this, and I'm going to propose alternatives for all:
I only want one element of the array
I want an optional argument
I want to pass a container
Let's start with the first, shall we? If you only want an element of the array, why bother with pointers and array in general? You can just use:
void funct(double);
and be done with it. And if you want to modify that double, why not pass it by reference?
void funct(double&);
and call the function as:
funct(vector[0]);
The number two has two very possible answers. One is to use function overloading like this:
void funct();
void funct(double);
And basically consider the function with no argument and an argument. The simplest solution is probably the right one, correct?
Otherwise, if you are really feeling fancy and you can't be bothered to write funct two times, you can even use boost::optional or std::optional (C++14), which clearly express the intent of the argument:
void funct(std::optional<double> optional) {
if (optional) {
// we have a double
} else {
// we don't have a double
}
}
And finally, the third one has three possible answers (can you see the pattern?).
If you only want a specific kind of container (why would you want that, only God knows) you can simply do:
void funct(const std::vector<double>&);
Otherwise you can either use templates like Bartek explained below or use my favorite solution: iterators (which is the choice of standard algorithms as well, just to make it less official).
And guess what? It works also with C-style arrays (which you shouldn't be using by the way). Here's the solution:
template<class Iterator>
void funct(Iterator begin, Iterator end) {
for (auto it = begin; it != end; ++it) {
// do something to element (*it)
}
}
And BOOM. You can use it like this:
double x[100];
funct(std::begin(x), std::end(x));
or:
std::vector<double> x(100);
funct(x.begin(), x.end());
Happy coding.
std::vector has member function data. So you can use it like this:
func(nyVec.data());
I did not find in the Standard that if a vector is empty then data has to return 0. Maybe it is a Standard defect. Though an empty vector can has non-zero capacity.
If you need to check whether a vector is empty then you can write:
func(myVec.empty() ? NULL : nyVec.data());
Usually if you pass an array by value you should specify a second parameter that will contain the size of the array. So maybe it would be better if func was declared as:
func(double *, std::vector<double>::size_type);
In this case you could call the function as:
func(myVec.data(), myVec.size());
If you need to process only one element then the standard approach is the following:
if (!myVec.empty()) func(&myVec.front());
Try
funct(&myVec.at(0));
This performs bounds checking and will throw std::out_of_range if element is not within the range of the container.
Create a utility function. This will both hide the not-niceness and prevent code duplication.
template <class T>
typename T::value_type* first_ptr(T &&container)
{
return container.empty() ? nullptr : &container.front();
}
int main()
{
funct(first_ptr(myVec));
}
I would wrap or change the function into more idiomatic optional primitive:
void funct(optional<double&> f);
Let's think about the passing then. The function should, if the vector is not empty, pass the first element, and nothing otherwise.
Directly transcribes to
if (!v.empty()) {
funct(v.front());
} else {
funct(none);
}
I would probably change it to regular value semantics, though; referencing elements from collections directly is rather dangerous.
Of course you can pack it into a reusable function:
template<class Container>
optional<typename Container::value_type&> myFront(Container& cont) {
if (!cont.empty())
return cont.front();
else
return none;
}
funct(myFront(v));
Now you only need lift :).
std::vector data() member function returns a pointer to its internal data (array), so we can use it this way:
if ( !(myVec.size() == 0)) func( myVec.data());
or:
if ( !myVec.empty()) func( myVec.data());
The choose of size() or empty() is dependent on implementation of these functions that you are using. C++ standard guarantees that empty() is constant time for all standard containers.
Not really an answer but anyway: this seems like an XY problem.
I would say none of the solutions proposed in the OP are good fits based on the following: it makes little sense to be calling a function with a null pointer argument so I would say this should be handled at the call site. Something like:
if(!myVec.empty()) funct(&myVec[0]);
else ...

Array as parameter

I was wondering which one of these is the best when I pass an array as parameter?
void function(int arr[]) {...};
or
void function(int* arr) {...};
Could you tell me your reason? and which book you might refer to? Thanks!
Since this question is tagged c++, I would use neither. If you must use this, both are equivalent.
But since you use C++, a better approach is to use a std::vector for such tasks
void function(std::vector<int> &arr) {...}
or, if you don't modify the array/vector
void function(const std::vector<int> &arr) {...}
If you just want to pass any array (including dynamically allocated), they are equivalent.
Should your function require an actual fixed-size array, you could do this:
template <size_t N>
void function(char (&str)[N]) { ... }
They are semantically identical.
#1 is slightly better (in my opinion) because it makes it explicit that you are passing an array.
You ask which to choose of
void function(int arr[]) {...};
and
void function(int* arr) {...};
The latter allows you to declare the pointer itself as const, while the former only allows you to declare the items as const. However, to the reader [] indicates an array as opposed to possibly a pointer to a single object. Personally I think the constraint offered by const is more practically useful than the indication of array'ness offered by [].
For higher level code, use std::vector or std::array, whichever is more appropriate.
The best way to pass an array as a parameter is actually:
void function(type_t* array, int amountOfElts, int arrayAllocatedElts);
For some cases (like when passing strings) you can often skip these two parameters. But they may be useful either way, for example when doing some operations on the string, or they may save you a strlen call or two.
Using the [] option in function arguments is in my opinion confusing and should be avoided. But I don't think it's a convention.
Depending on the layer of abstraction you want to provide, you should chose between Olaf's approach or something STL uses to the great level:
template <class Iter>
void function(Iter first, Iter last)
{
// for example, to get size:
std::size_t size = std::distance(first, last);
// for example, to iterate:
for ( Iter it = first; it != last; ++it )
{
// *it to get the value, like:
std::cout << *it << std::endl;
}
}
That way, you can use the function not only for arrays, but for various STL types: vectors, lists, queues, stacks and so.
int tab[4] = {1,2,3,4};
function(tab, tab+4);
std::vector<int> vec;
// fill vector with something
function(vec.begin(), vec.end());

Using arrays as a template parameters in my rudimentary vector class

Coming from a PHP background, I'm trying to learn C++, since I find it an interesting language. As a practice I want to create a simple Vector class using templates, which is not to hard. However, I run into one problem.
I have created the following template class:
template <typename T>
class Vector
{
public:
Vector(int length);
~Vector(void);
int getLength();
T& operator[] (const int index);
private:
T *_items;
int _count;
};
template <typename T>
Vector<T>::Vector(int length)
{
_items = new T[length];
_count = length;
}
template <typename T>
T& Vector<T>::operator[]( const int index )
{
if (index >= getLength() || index < 0)
throw exception("Array out of bounds.");
return _items[index];
}
All functions are implemented, but they're not relevant to my question, so I haven't copied them here.
This class works as expected, with one exception:
If I want to create a vector of array's, it doesn't work.
e.g.:
Vector<int[2]> someVector(5);
What I obviously want is that the _items property of the vector class will be an int[5][2]. However, since the compiler replaces the 'T' with 'int[2]', the _items property will be int[2][5] (or at least, that's what I understood from debugging, please correct me if I'm wrong). As a result, the [] operator doesn't work correctly anymore, and therefore this whole class is useless for arrays.
Is there a way to solve this problem, so that this class also works for arrays? And if that's not possible, is there a way to prevent this class being initialized with arrays?
Edit: Thanks for all your responses so far. However, I might have been not entirely clear with my question. First of all, I created this class to get used to c++, I know there is a std::vector class, and I also now that it's better to use a vector of vectors. That's not really the problem. I just want to understand templates better, and c++ in general, so I want to know how to deal with this type of problems. I want to be able to create classes which don't make the program crash. If I, or someone else, would use this class right now and tried to use primitive arrays instead of vectors for this class, at some point the program will crash since the array is wrong (Vector(y) becomes int[x][y] instead of int[y][x] internally). So I want a solution which either creates the correct array, or prevents the vector being initialized with arrays at all.
Quite simply, don't ever use the in-built primitive arrays. For anything. They suck, tremendously. Always use a class wrapper such as boost::array, if you don't have TR1 or C++0x both of which also provide an array class. A Vector<boost::array<int, 2>> will trivially compile.
Why not use primitive arrays?
They have hideous implicit conversions to pointers, forget their size at the drop of a hat, aren't first-class citizens (can't assign to them, for example), don't check their bounds, for example. boost::array<int, 2> is exactly a primitive array without crappy conversions, is fully generic- for example, your Vector template works fine with a boost::array<int, 2> off the bat, and it can do bounds checking in the at() function.
I'm not suggesting using a dynamic array instead. boost::array is not a dynamically sized array. It is a constant size, value type array, that will not convert to a pointer, it has functions for use in the Standard library like begin, end, size, and it can be treated like any other type- unlike arrays, which have a dozen special rules- as you've found out.
I see a few things wrong with this.
If you are making a generic vector class, why deal with a vector of arrays rather than a vector of vectors?
Rather than defining a vector of type int[2], try making a vector of vectors of size 2 with something like this:
Vector<Vector<int>> vector(5);
for (int i = 0; i < 5; i++)
{
vector[i] = Vector<int>(2);
}
Rather than using a constant sized array, try using a pointer.
Rather than using a pointer to arrays of size 2, use a pointer to a pointer, and allocate two spaces for that pointer. Pointers are a lot easier to deal with in C++ because you can simply pass the address of the pointer rather than having to copy the entire array. It's generally very bad form to pass arrays.
Add a default parameter to your constructor
Rather than declaring the constructor with Vector(int length);, try using Vector(int length = 0); so that if the user doesn't specify a length it will default to a size of zero.
Finally, are you aware that there is in fact an std::vector, or are you aware of this and simply trying to replicate it? Templates are known to be one of the hardest subjects of C++, good luck!
The condition must say index >= getLength(), because getLength() is not an allowed index value too (the first element's index is 0, the last's is getLength()-1)