4

I am trying to connect two existing codebases — one in C, the other in C++. The C++ code uses std::vector whereas the other one is based on arrays of double. I would like to pass arrays of double from the C code, perform operations on std::vectors in the C++ code, and eventually have these operations reflected in the arrays of double.

Is it possible to create a std::vector that matches the memory occupied by the array of double?

I have tried several options, but they all involve the creation of a new vector and a copy of the array of double into that vector. For instance:

void fcn(double* a, int sizeofa)
{
    std::vector<double> vect_a;
    vect_a.assign(a, a + sizeofa);

    // operations on vect_a

    for (int i=0;i<sizeofa;i++) { a[i] = vect_a[i]; }
}
Nick Matteo
  • 4,453
  • 1
  • 24
  • 35
vspsonn
  • 57
  • 4
  • 5
    No, that's not possible because `std::vector` needs to manage its own memory. Also, even if you could pass in your buffer, how would it know how to reallocate (and so, how to free the buffer you passed in)? – milleniumbug Jun 23 '16 at 22:56
  • 1
    What operations do you want to perform? – Striker Jun 23 '16 at 23:00
  • Well you can't have C and C++ code in the same translation unit obviously. You will have to use `extern "C"` to wrap the C API, and then do `c_func(v.data(), v.size())` or something similar. – uh oh somebody needs a pupper Jun 23 '16 at 23:00
  • if the data is originating on the *C* side and it's okay to manipulate the array directly rather than working off a copy, it might be prudent to look into the GSL's `span`, to allow the C memory should be managed with C code, while tying data location and length information together on the C++ side to eliminate out-of-bounds access. – jaggedSpire Jun 23 '16 at 23:02
  • 3
    @milleniumbug Kind of missing the point here. It's pretty clear OP has an XY problem. – uh oh somebody needs a pupper Jun 23 '16 at 23:03
  • Possibly related: [Wrap existing memory with const std::vector?](http://stackoverflow.com/q/22622013/364696). Note that for something like `double`, the `reference_wrapper` solution given is a false savings; storing a `vector` of references uses just as much storage as storing a `vector` of `double`s on more 64 bit systems (half as much on more 32 bit systems), but the need to operate through an additional layer of indirection for all elements in the `vector` would usually eliminate any savings on work performed. – ShadowRanger Jun 23 '16 at 23:07
  • If you can create the vector first and pass its internal buffer to the `C` code, that could work. – Galik Jun 23 '16 at 23:19
  • @ShadowRanger I'm not sure he's looking for execution efficiency, just to simplify the implementation. He doesn't want to have to write a wrapper for every function that performs the conversions between array and vector. – Barmar Jun 23 '16 at 23:19
  • It indeed smells XY problem. – SergeyA Jun 24 '16 at 02:13
  • 1
    The technical challenges seem very similar to those discussed in [this question](http://stackoverflow.com/questions/8049657/stack-buffer-based-stl-allocator), given the real need is use of an arbitrary memory region and whether that's from the stack or C's malloc or whatever's largely irrelevant. So the techniques in the answers there should be useful, but you'll have to instantiate `std::vector` with a custom allocator - might or might not be convenient/practical for you. – Tony Delroy Jun 24 '16 at 02:27

2 Answers2

4

As noted in the comments, std::vector manages its own memory, you can't make it use some other memory as the backing store (it would have no idea what to do if the size changed, among other issues).

But you may not need a vector at all; if you're just using vector for non-dynamic size related features, it's highly likely you could just use the functions from <algorithm> to perform the same work directly on the array that you wanted to use vector's methods to accomplish.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • It seems like he's trying to do this without rewriting the code that expects a vector. Your suggestion requires recoding that to use ``. – Barmar Jun 23 '16 at 23:15
  • 1
    Thanks for your answer. The issue is indeed that I have to connect the two existing codes, and `// operations on vect_a` actually contains a bunch of call to functions on the cpp side... – vspsonn Jun 23 '16 at 23:16
  • 1
    @vspsonn: If you're calling outside code that can't handle anything but `vector`s, then you need to bite the bullet and make a `vector`. The code you gave for converting is needlessly verbose (setup can be just `std::vector vect_a(a, a + sizeofa);`, copy back can be just `std::copy(std::begin(vect_a), std::begin(vect_a) + std::min(sizeofa, vect_a.size()), a);`, but if you potentially need to support the complete range of `vector` behaviors, make a `vector`. – ShadowRanger Jun 24 '16 at 01:00
  • @immibis: `a + sizeof a` is not the end of the array, but that's not what I typed. The OP named the variable `sizeofa` (all one word, no spaces), which I'm assuming is the length in elements under a silly name. If I'm wrong, well, that's the OP's issue; no reasonable non-I/O oriented function accepts the array length in bytes, and they should be ashamed of themselves. :-) – ShadowRanger Jun 24 '16 at 01:40
3

In C++, functions requiring a container often denote the container by Iterator pairs, which are templated. This is very convenient, especially when interfacing with external libraries, because an iterator isn't a type. It is a concept, which is just an interface that defines what a type should look like. Turns out, C style pointers are valid iterators. This means that you can use any C++ function that accepts an iterator with any C array.

So, now to answering your question. In other answers, it was made clear that you cannot make a std::vector control the memory allocated by a C array because a std::vector requires full ownership over the data because it wouldn't know how to deallocate it. You can copy the C array into a vector, but there is no point in using a std::vector unless you want it's resizing capabilities.

In summary: try not to pass std::vectors into functions because iterators are more generic. If you must avoid templates (virtual function, etc) than use a C style array because those are very flexible too, you can turn a std::vector into a C array, but the other way requires a copy.

I know this is hard if you have already made your code interface with std::vectors, in which case a copy is the only possible way. Prefer C style arrays when you don't need to resize the array, and maybe in the future std::array_view

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Russell Greene
  • 2,141
  • 17
  • 29