How to Cheaply Assign C-Style Array to Std::Vector

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.

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

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

w_.assign(w, w + len);

How to make a std::vectorT use an existing T* array without copying those values?

There is no interface into vector to make it take ownership of your pre-existing buffer. Even if you could shoe-horn it into the vector by using a custom allocator that provides this memory's address, the vector will consider it raw memory and overwrite it.

If it must be a vector, then you're out of luck without copying.

However, some sort of adaptive view on the existing buffer could give a container-like interface over your array without copying (such as the gsl::span as suggested in comments by Justin.)

gsl::span<int> s(myPtr, 4);

see https://github.com/Microsoft/GSL
and http://codexpert.ro/blog/2016/03/07/guidelines-support-library-review-spant/

How do I copy a C-style array into a void pointer in C++?

  1. As already commented above, using void* is not very useful.
  2. If you need an array object, it's recommended in C++ to use either std::array for a fixed size array, or std::vector for dynamic size array.
  3. This line: array_private = pass_array_here is simply assigning the pointer, not copying the array content.
  4. If you use std::array or std::vector as suggested in point 2 above, you can utilize the copy constructor of these classes to actually copy the array's content easily:
    void foo(std::vector<SomeType> const & pass_array_here) {
array_private = pass_array_here;
}

  1. If the caller of the function foo does not need to use the array after calling the function, you can save the copy of the data, and utilize C++ move semantics (available since C++ 11):
    void foo(std::vector<SomeType> && pass_array_here) {
array_private = std::move(pass_array_here);
}

  1. If the caller does not have a std::vector but an old C style array, it is possible to initialize the std::vector member from it (which will copy the data). See: std::vector::assign.

For 4, 5 and 6 above, your private data member will have to be defined as:

std::vector<SomeType> array_private; 

  1. If you need to access the data buffer managed by an std::vector, you can use std::vector::data: std::vector::data. You can cast this data pointer into a void* if you need to pass it to a C style function, e.g. in opengl (no need to copy the data).

  2. More about move semantics and R value references here: Understanding rvalue references

C++ equivalent for C-style array

Question: is there an equivalent in C++ for C-style arrays in terms of performance?

Answer: Write C++ code! Know your language, know your standard library and use it. Standard algorithms are correct, readable and fast (They know the best how to implement it to be fast on the current compiler).

void testC()
{
// unchanged
}

void testCpp()
{
// unchanged initialization

for(j=0;j<1000;j++)
{
// how a C++ programmer accumulates:
count = std::accumulate(begin(v), end(v), 0);
}

// unchanged output
}

int main()
{
testC();
testCpp();
}

Output:

(C) For loop time [ms]: 434.373
1000000
(C++) For loop time [ms]: 419.79
1000000

Compiled with g++ -O3 -std=c++0x Version 4.6.3 on Ubuntu.

For your code my output is similiar to yours. user1202136 gives a good answer about the differences...

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

Convert char** (c) of unknown length to vectorstring (c++)

You can simply use the constructor of std::vector that takes two iterators:

const char* arr[] = {"Hello", "Friend", "Monkey", "Face"};
std::vector<std::string> v(std::begin(arr), std::end(arr));

Or if you really have a const char**:

const char** p = arr;
std::vector<std::string> v(p, p + 4);

Which will also work with directly using arr instead of p due to array-to-pointer conversion.

Replace fixed size arrays with std::array?

AFAIK std::array just provides a nicer STL-like interface to deal with rather than normal C-arrays. In terms of performances and capabilities the two choices boil down to be pretty much the same but std::array can be used as a standard container.

Another feature: they might be treated like tuples since they provide tuple-like access functions.

Last but not the least as user2079303 noticed: if your code is going to be used by novice programmers, it can prevent the array decaying process when passing it as an argument.

If you're wondering if you should just replace all your C-style arrays with std::arrays, the answer is yes if you're going to exploit some of the newly available features and/or rewrite some of your code to take advantage of those capabilities. If you're just plain substituting C-arrays with std::arrays (without touching anything else) it might not be worth it.

C++ Move constructor for object with std::vector and std::array members

[...] and set the other's content to their default values?

No. When not stated otherwise a moved from object is in a valid, but unspecified state. Setting all elements to some default would be rather wasteful.

Further, a std::array does contain the elements. Its not just a pointer to some dynamically allocated elements that could cheaply be moved. The elements are right within the array. Hence you can only move the individual elements, the array as a whole can only be copied. A std::array is moveable when its elements are moveable, otherwise moving it will merely make a copy. For details I refer you to Is std::array movable?.

TL;DR

Vector(Vector&& other) = default; is fine. You just expected it do something it does not do. Neither does moving set the moved from elements to some default, nor does moving the std::array<size_t,2> actually move the elements, rather it copies them.



Related Topics



Leave a reply



Submit