9

Assume I have a C library API function which takes pointer of pointers as parameter. However since I am programming in C++ I would like to take advantage of std vector to deal with the dynamic memory. How can I efficiently convert vector of vector into pointer of pointer? Right now I am using this.

#include <vector>

/* C like api */
void foo(short **psPtr, const int x, const int y);    

int main()
{
    const int x = 2, y = 3;
    std::vector<std::vector<short>> vvsVec(x, std::vector<short>(y, 0));
    short **psPtr = new short*[x];

    /* point psPtr to the vector */
    int c = 0;
    for (auto &vsVec : vvsVec)
        psPtr[c++] = &vsVec[0];

    /* api call */
    foo(psPtr, x, y);        

    delete[] psPtr;
    return 0;
}

Is this the best way to achieve the goal? Can I get rid of the "new delete" thing by using iterator or some std method in this case? Thanks in advance.

Edit: According to answers I am now using this version to interface with C code. I am posting it here.

#include <vector>

/* C like api */
void foo(short **psPtr, const int x, const int y);    

int main()
{
    const int x = 2, y = 3;
    std::vector<std::vector<short>> vvsVec(x, std::vector<short>(y, 0));
    std::vector<short*> vpsPtr(x, nullptr);

    /* point vpsPtr to the vector */
    int c = 0;
    for (auto &vsVec : vvsVec)
        vpsPtr[c++] = vsVec.data();

    /* api call */
    foo(vpsPtr.data(), x, y);        

    return 0;
}

Looks more C++ like to me. Thanks for all!

yc2986
  • 1,101
  • 3
  • 20
  • 23
  • 3
    Drop one level of vector and take the address of a pointer to the first element of that flat vector. – rubenvb Feb 22 '17 at 19:13
  • Only making it looks nicer, you can replace psPtr with a vector, and set it up with some function in algorithm. – BlueWanderer Feb 22 '17 at 19:21
  • The API function either needs a size parameter or has the convention that a null pointer denotes the last element, in which case you must add a `nullptr` at the end. – Christian Hackl Feb 22 '17 at 19:28
  • @ChristianHackl Thanks I will update it. I am not so familiar with C convention. Correct me if I am wrong. – yc2986 Feb 22 '17 at 19:29
  • @yc2986: Well, I thought you were talking about a real function :) But in any case, the function must have some way to know the size (or the sizes). What should it do if it just receives a single pointer *and* there is no convention to represent the last element(s)? How could you ever hope to implement such a function? – Christian Hackl Feb 22 '17 at 19:33

2 Answers2

4

Is this the best way to achieve the goal?

If you are sure that the vector of vectors will outlive psPtr, then yes. Otherwise, you run the risk that psPtr will contain invalid pointers.

Can I get rid of the "new delete" thing by using iterator or some std method in this case?

Yes. I suggest using:

std::vector<short*> psPtr(vvsVec.size());

and then use &psPtr[0] in the call to the C API function. That removes the burden of memory management from your code.

foo(&psPtr[0]);        
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • This looks pretty neat. Never thought of vector of pointer before. Thanks! – yc2986 Feb 22 '17 at 19:26
  • @yc2986: A vector of pointers is usually an anti-pattern. If you never thought of doing this, this is actually a good thing. – IInspectable Feb 22 '17 at 19:50
  • 1
    @IInspectable Thanks for the info. I think for everything C++ project I will never do this. But for interfacing with C code it may have some value. I will never do thing like generating a vector of pointer then point each of them to "new" allocated objects and manually delete them. – yc2986 Feb 22 '17 at 19:54
3
std::vector<short*> vecOfPtrs;
for (auto&& vec : vvsVec)
    vecOfPtrs.push_back(&vec[0]);

foo(&vecOfPtrs[0]);
rlbond
  • 65,341
  • 56
  • 178
  • 228
  • Since you know the size of the container `vecOfPtrs` ahead of time, you should really initialize it to that size. This prevents potential memory relocations, and potential exceptions due to resizing. – IInspectable Feb 22 '17 at 19:53
  • Why `&vec[0]` and not `vec.data()`? I can think of at least 3 reasons to use `vec.data()` over `&vec[0]`, and zero to use `&vec[0]` over `vec.data()`. (empty vectors, `vector`, `std::addressof` issues, in decreasing importance) – Yakk - Adam Nevraumont Feb 22 '17 at 20:16
  • @Yakk I guess old habits die hard from C++03. `vec.data()` is superior. However, your first reason isn't good at all since `vec.data()` should return `&vec[0]`, even for an empty vector, and the C++ standard allows taking the address of one-past-the-end of an array. – rlbond Feb 23 '17 at 00:06
  • @rlbond you cannot call `v[v.size()]` -- it is equivalent to `*(v.begin()+v.size())`, which is `*v.end()`, even if you immediately `&` it; dereferencing an `end` iterator is illegal in `vector`. Niw this may be unlikely to format your drive, but it generating run time debug messages seems likeky. – Yakk - Adam Nevraumont Feb 23 '17 at 00:54