0

I'm new to C++11 and I'm confused about the usage of std::refence_wrapper class.

let's consider the example shown in https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper ,which shuffles the elements contained in a standard std::vector, i.e:

std::vector<int> l(10); 
std::iota(l.begin(), l.end(), -4);
std::vector<std::reference_wrapper<int>> v(l.begin(), l.end());
std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

Now, if consider the original vector l, I have that l.data() returns a pointer to the internal array, which can I use in a C application.

Instead, it's not clear to me instead what is returned by v.data(). I tried various combinations of surely wrong casts, such as int* p = (int*)(v.data()->get()) without obtaining correct results (the swapped values).

My goal is to interface a C++ application (which gives me a vector of reference wrappers) with an old C library. Can you point me which is the most correct way to obtain a C-like array from the vector v, after the shuffle shown in the example? Do I need to copy all the elements one-by-one in another vector? Is there any C++11 class which can help me in the job? Thank you

  • 1
    In your code, `l` is a `list`, not a `vector`. It doesn't have a `data()` member function and if it did it wouldn't point to a C-style array. – Daniel H Feb 14 '19 at 19:08
  • I'm sorry, I made a mistake copy & pasting the snippet. I edited the question, so now l is a vector. – Marco Randazzo Feb 14 '19 at 19:58
  • Why do you need `std::reference_wrapper` in the first place? Do you plan to access the original array through these references? – n. m. could be an AI Feb 14 '19 at 20:13
  • 1
    @n.m. yes. The general idea is similar to the one reported in https://codereview.stackexchange.com/questions/114658/return-row-or-column-from-a-2d-array in which multiple std::vector> provide different 'views' of the internal data structure. Of course, when I access to the elements of the vector> I want to modify data in the original data structure. But in this question, when I speak about a C-array obtained by .data() method, I just want to read data, not to modify it. – Marco Randazzo Feb 14 '19 at 20:42

2 Answers2

5

reference_wrapper is a C++ type; you're not supposed to be able to just hand it over to a C API. If you want to pass something to a C API, then it needs to be something that C and C++ share.

If that C API takes an array of pointers to integers, then pointers to integers is what your vector should store. Otherwise yes, you have to copy those integers into something that C can speak.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
0

After more thinking, I came up with this solution:

std::vector<int> l(10); 
std::iota(l.begin(), l.end(), -4);
std::vector<std::reference_wrapper<int>> v(l.begin(), l.end());
std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

std::vector<int> vec2 (v.begin(), v.end());
int* p = vec2.data();

I'm thus copying the elements from v to a new vector vec2. The C array p obtained from vec2 is now valid.

I wonder if there is a better way to do the job...

  • If C expects an `int*`, then you have to have either a `int[]` or a `vector` that holds the final data. There's no "better" way. – Mooing Duck Feb 14 '19 at 22:12
  • If you can change the C to expect an array of `int` pointers, then you can have a `vector` the entire time. You need to manually handle the derefencing then instead of letting `std::reference_wrapper` do it but it doesn't take an extra copy for the C side. – Daniel H Feb 15 '19 at 07:18