Yontzzi
Yontzzi

Reputation: 361

Taking part of std::vector C++

In my code I have something like this:

struct SomeStruct
{
  int test1;
  int test2;
  float test3;
  float test4;
};
std::vector<SomeStruct> SomeStructs;

I am looking for a way to get a part of that vector in a continues manner, So that I can access it with a pointer or a c-array.

Suppose I want a pointer to access only the part of the struct that are test2. I want to pass that part of the vector to a C API, Is it possible?

I'm trying to avoid creating a new std::vector/c-array.

How It look's like in memory(kind of):

enter image description here

Upvotes: 2

Views: 234

Answers (5)

ytobi
ytobi

Reputation: 673

If i got you well, i think its possible.

struct SomeStruct
    {
        int test1;
        int test2;
        float test3;
        float test4;
    };

   int size = 3;// whatever size

   vector<SomeStruct> myStruct(size);
    myStruct[0].test1 = 0;
    myStruct[1].test1 = 1;
    myStruct[2].test1 = 2;

    /* myPtest1 will allow you to get the test1 part of myStruct in a 
    contiguous memory manner*/ 

    int *myPtest1 = new int(myStruct.size());

    for(int i = 0; i< myStruct.size(); i++)
        myPtest1[i] = myStruct[i].test1;

    // for illustration.
    cout << myPtest1[0] << endl; // 0
    cout << myPtest1[1] << endl; // 1
    cout << myPtest1[2] << endl; // 2

You can now pass myPointer to your API, myPointer gives you access to only test1 part of myStruct vector. you can do same for the rest of the SomeStruct attributes.

Upvotes: 0

arboreal84
arboreal84

Reputation: 2154

To implement this in an idiomatic manner you will need to roll your own custom iterator that returns that field specifically.

Take a look at c++ how to create iterator over one field of a struct vector

C and C++ interoperability is a vastly different problem. To simplify things you may just want to implement it in C.

Upvotes: 0

Francesca Nannizzi
Francesca Nannizzi

Reputation: 1705

There's no way to access just the contents of each test2 from a pointer or array, because the test2 members are not contiguous in memory even if the structs in the vector are. There's other data in the struct, so you need to skip over that to read each test2.

When you find yourself asking a question like this, try thinking about other data structures you can use that would make the problem easier to solve. For this case, perhaps a std::unordered_map would be a good choice.

std::unordered_map<int,SomeStruct> map;
// make a struct...
map.insert(std::make_pair<int,SomeStruct>(a_struct.test2,a_struct));
// add a bunch more structs...
// get an iterator to all the keys in the map (ie. something like a pointer to all test2 members)
key_iterator = map.begin()

Upvotes: 0

7raiden7
7raiden7

Reputation: 359

If you want to access it in a for loop you can do:

for (const auto& iterator: SomeStructs)
{
    const int& test2 = iterator.test2;
    // do what you need to do
}

If you need the j-th element:

const int& test2 = SomeStructs[j].test2

In this way you are not making extra copies but you are directly referencing items from vector. Remove const if you need to change the value

Upvotes: -1

Nir Friedman
Nir Friedman

Reputation: 17704

No, what you are asking for is impossible. Quick review:

  1. We can clearly see that the test2 entries of the struct are not currently laid out contiguously in memory, because they are just one member of a struct that is contiguous, so clearly the other struct elements sit in between each occurence of test2.
  2. You want them to be contiguous, so you need a different memory layout than you currently have.
  3. You don't want to create a new vector or array, so you are stuck with your current memory layout, which is wrong.

Your options are like so:

  1. Change the variable to be say 4 vectors of variables instead of one vector of structs.
  2. Create a new vector when you need one.
  3. Don't use a C API that requires contiguous memory.

For 3 it is worth noting that some C APIs, notably BLAS, supported "strided" arrays which means that there is a fixed size gap between elements, which would solve this issue for you.

Upvotes: 4

Related Questions