How to Initialize Std::Vector from C-Style Array

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

Don't forget that you can treat pointers as iterators:

w_.assign(w, w + len);

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

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]) );

Initialize std::vector std::string from a C style string array

Yes, easily, using the iterator-pair constructor:

#include <iterator>
#include <string>
#include <vector>

std::vector<std::string> v(std::begin(names), std::end(names));

How to cheaply assign C-style array to std::vector?

The current std::vector doesn't provide any capability or interface to take ownership of previously allocated storage. Presumably it would be too easy to pass a stack address in by accident, allowing more problems than it solved.

If you want to avoid copying into a vector, you'll either need to use vectors through your entire call chain, or do it the C way with float[] the entire time. You can't mix them. You can guaranteed that &vec[0] will be equivalent to the C-array though, fully contiguous, so using vector in the whole program may be feasible.

Initialize std::vector with given array without std::allocator

Magic

This answer is magic, dependent on the implementation of the compiler.

We can forcibly access the container of a vector.

Take g++ as an example. It uses three protected pointers, _M_start, _M_finish, and _M_end_of_storage to handle storage. So we can create a derived class that sets/resets the pointers to the return of vaule bar() in the constructor and destructor.

Example code for g++:

static_assert(__GNUC__ == 7 && __GNUC_MINOR__ == 5 && __GNUC_PATCHLEVEL__ == 0);

class Dmy: public std::vector<int>
{
public:
Dmy(int *b, int *e)
{
_M_impl._M_start = b;
_M_impl._M_finish = e;
_M_impl._M_end_of_storage = _M_impl._M_finish;
}

~Dmy()
{
_M_impl._M_start = 0;
_M_impl._M_finish = 0;
_M_impl._M_end_of_storage = 0;
}
};

foo(Dmy(data, end_of_data));

Use std::vector for std::array initialization

I would propose:

template<typename T, typename Iter, std::size_t... Is>
constexpr auto to_array(Iter& iter, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{ ((void)Is, *iter++)... }};
}

template<std::size_t N, typename Iter,
typename T = typename std::iterator_traits<Iter>::value_type>
constexpr auto to_array(Iter iter)
-> std::array<T, N> {
return to_array<T>(iter, std::make_index_sequence<N>{});
}

This deduces the element type from the iterator and leaves copy-vs-move semantics up to the caller – if the caller wants to move, they can opt-in via std::move_iterator or the like:

auto initFoos() {
constexpr unsigned n{123};

std::vector<Foo> lst;
for (unsigned i{}; i != n; ++i) {
lst.push_back(getNextFoo(lst));
}

// copy-init array elements
return to_array<n>(lst.cbegin());

// move-init array elements
return to_array<n>(std::make_move_iterator(lst.begin()));
}

Online Demo


EDIT: If one wants to override the deduced element type, as indicated in the comments, then I propose:

template<typename T, typename Iter, std::size_t... Is>
constexpr auto to_array(Iter& iter, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{ ((void)Is, T(*iter++))... }};
}

template<std::size_t N, typename U = void, typename Iter,
typename V = typename std::iterator_traits<Iter>::value_type,
typename T = std::conditional_t<std::is_same<U, void>{}, V, U>>
constexpr auto to_array(Iter iter)
-> std::array<T, N> {
return to_array<T>(iter, std::make_index_sequence<N>{});
}

This leaves the element type optional but makes it the second parameter rather than the first, so usage would look like to_array<N, Bar>(lst.begin()) rather than to_array<Bar, N>(lst.begin()).



Related Topics



Leave a reply



Submit