vector struct in vector struct in - c++

Whats wrong in this code?
#include <vector>
#include <iostream>
typedef struct {
float x, y, z;
} aaa;
typedef struct {
float r, g, b;
std::vector<aaa> a;
} bbb;
typedef struct {
float s, t, p;
std::vector<bbb> b;
} ccc;
int main()
{
aaa o;
std::vector<ccc> c;
c.resize(1); // its OK
c[0].b.resize(4); // its OK
c[0].b[0].a.resize(2); // ??? its allocate 4 instead of 2 but why?
c[0].b[1].a.resize(2); // its OK
c[0].b[2].a.resize(2); // its OK
c[0].b[3].a.resize(2); // its OK
o.x = 1.0f;
o.y = 0.5f;
o.z = 2.567f;
c[0].b[0].a.push_back(o);
o.x = 0.0f;
o.y = 3.4f;
o.z = 3.67f;
c[0].b[0].a.push_back(o);
std::cout << c[0].b[0].a[0].x << std::endl;
std::cout << c[0].b[0].a[0].y << std::endl;
std::cout << c[0].b[0].a[0].z << std::endl;
std::cout << c[0].b[0].a[1].x << std:: endl;
std::cout << c[0].b[0].a[1].y << std::endl;
std::cout << c[0].b[0].a[1].z << std::endl;
system("pause");
return 0;
}
And here is watch window output:
vector c: size = 1; // its OK
vector b: size = 4; // its OK
vector a[0]: size = 4; // ??? (4) ???
vector a[1]: size = 2; // its OK
vector a[3]: size = 2; // its OK
vector a[4]: size = 2; // its OK

std::vector::resize() resizes the vector. So you resize it to 2, and then add 2 more items (with push_back()), so your size is 4.
As mentioned in the comments, if you use
std::cout << "c[0].b[0].a.size() = " << c[0].b[0].a.size() << std::endl;
at different points in the code, you will see the the appropriate sizes.

Member function resize creates new elements if the current size of a vector is less than the size specified in resize().
Member function push_back appends new elements to the vector.
So after statement
c[0].b[0].a.resize(2);
vector a will have two elements. And after these two statements
c[0].b[0].a.push_back(o);
//...
c[0].b[0].a.push_back(o);
it will be appended with another two new elements. Thus as a result vector a will have 4 elements.
If you want to have only two elements then you have to write the following instead of using function push_back
c[0].b[0].a[0] = o;
//...
c[0].b[0].a[1] = o;

Related

Create two vectors contain the same elements in different order

Is it possible to create a vector from elements of another vector so that changing an element by index in one of the vectors results in a change in the corresponding element in the second vector?
std::vector<double> temp_1 = {1, 4};
std::vector<double> temp_2;
temp_2.resize(3);
temp_2[0] = temp_1[1];
temp_2[1] = temp_1[0];
temp_1[0] = 55;
>>> temp_1 =[55,4]
>>> temp_2 =[4,55]
I can be done using pointers or reference wrappers, though note that any reallocation of the referenced vector will render the references invalid. However, if no reallocations are involved, it should be fine.
#include <vector>
#include <functional>
#include <iostream>
int main(int, char*[])
{
std::vector<int> x{1,2,3};
std::vector<std::reference_wrapper<const int>> y {
x[2], x[0], x[1]
};
std::cout << "y before modifying x\n";
for (auto el: y) {
std::cout << el << '\n';
}
x[1] = 8;
std::cout << "y after modifying x\n";
for (auto el: y) {
std::cout << el << '\n';
}
}
https://godbolt.org/z/d41nxPffz

Using vector::data() chaining with member function print differnet values as pointer arithmetic

I have a class hello with a method which returns a vector member.
I am trying to print out values using vector::data() with pointer arithmetic, but I am facing an undefined behavior. See example below:
class hello
{
public:
std::vector<int> data()
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
int main(int argc, const char **argv)
{
hello h;
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
int *sa = h.data().data();
std::cout << "----------------------------" << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
return 0;
}
The result looks like this:
----------------------------
0x9e2ee0
1
0x9e2ee4
2
0x9e2ee8
3
0x9e2eec
4
----------------------------
0x9e2ee0
0
0x9e2ee4
0
0x9e2ee8
10289168
0x9e2eec
0
Why do *(sa + i) and *(h.data().data() + i) print different values?
sa + i and &*(h.data().data() + i) prints the same memory address, why I can not get the correct data just use this memory address (sa + i)
hello::data() is returning a vector by value, which means it will return a temporary copy of hello::v, which will allocate its own int array and copy the values from v.
When calling h.data(), that temporary vector will be destroyed when it goes out of scope at the end of the full statement that called h.data().
So, in your 1st loop:
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data().data() + i) << std::endl;
std::cout << *(h.data().data() + i) << std::endl;
}
This is perfectly valid code, as the temporary vector returned by each call to h.data() will not be destroyed until after its inner data has been printed.
However, in your 2nd loop:
int *sa = h.data().data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
In the statement that is calling h.data():
int *sa = h.data().data();
The temporary vector gets destroyed when it goes out of scope at the end of the statement, leaving sa to be a dangling pointer to freed memory, thus any use of sa inside the loop is undefined behavior.
sa + i and h.data().data() + i may point at the same memory address, but only if this last call to h.data() happens to create a new vector that reuses the same memory block that the temporary vectors in the 1st loop used, but that is not a guarantee. In any case, sa is pointing at freed memory, so it doesn't matter if the memory block was reused or not, the vector that owned that memory block is destroyed, freeing the memory, before the 2nd loop is entered. That is why you can't access the data, even if the memory addresses were the same.
To fix this issue, you need to change hello::data() to return a reference to hello::v instead, then no copy will be created, eg:
class hello
{
public:
std::vector<int>& data() // <-- note the &
{
return v;
}
private:
std::vector<int> v{1, 2, 3, 4};
};
Thus each call to h.data().data() will return a valid pointer to v's internal data, thus sa will not be a dangling pointer anymore.
Alternatively, have hello::data() return a pointer to v's data, rather than returning (a reference to) v itself, eg:
class hello
{
public:
int* data()
{
return v.data();
}
private:
std::vector<int> v{1, 2, 3, 4};
};
...
for (int i = 0; i < 4; i++)
{
std::cout << &*(h.data() + i) << std::endl;
std::cout << *(h.data() + i) << std::endl;
}
...
int *sa = h.data();
for (int i = 0; i < 4; i++)
{
std::cout << sa + i << std::endl;
std::cout << *(sa + i) << std::endl;
}
You returned a temporary copy of your vector. After the statement it is part of it is destroyed. If you wanted to keep it around you need to assign it to another vector.
So, you made a pointer to a temporary value which got erased. It no longer exists, and you're trying to point to pieces of its corpse.

How to change elements of a pointer to a vector?

Let's say I have a couple of vectors of integers and a pointer to a vector of integers. How would I go about changing the value of one element of the pointer to be the address in one of the other vectors of integers?
The context for this is that I've built a class that lets me bring in my desktop into the unreal engine, however on each tick it has to assign a form of vector that contains a struct to the values of another data class each tick, I instead wish to copy the memory addresses over for only a few of the elements (the pixel colour values) so I don't waste time by having to do a copy twice (which for a desktop image is millions of operations)
#include <iostream>
#include <vector>
using namespace std;
// Print function
void PrintVector(vector<int> v)
{
for( int i = 0; i < v.size(); i++ )
{
cout << v[i] << ", ";
}
cout << endl;
}
int main()
{
vector<int> vector1;
vector<int> vector2;
vector<int> *ptrvector;
//Do some assignment so the vectors have values
for( int i = 0; i<3; i++)
{
vector1.push_back(i);
vector2.push_back(2*i);
}
//Assign the pointer to the address of vector1.
ptrvector = &vector1;
//Print out:
PrintVector(vector1); // (1,2,3)
PrintVector(vector2); // (2,4,6)
PrintVector(*ptrvector); // (1,2,3)
// We should see that lines 1 and 3 are the same
//BROKEN BIT::
//Ideally want something like
ptrvector[0] = &vector2[2];
PrintVector(*ptrvector); // (6,2,3);
//Such that if I were to do this:
vector2[2] = 20;
PrintVector(*ptrvector); // It should change as a side effect: (20,2,3)
}
BONUS QUESTION:
Let's say I have this:
TArray<FColor> ColorData;
TArray<FColor> *ptrColorData
//Where TArray is essentially a vector. FColor is a struct with members (R,G,B,A)
//ColorData is initialised somewhere and we set the ptrColorData to the address
ptrColorData = &ColorData;
//Somewhere down the line we have a long loop whereby we do
ColorData[i].B = somedata[i];
ColorData[i].G = somedata[i+1];
ColorData[i].R = somedata[i+3];
//somedata is updated per tick, asigning ColorData per tick as well slows it down.
// I wish to be able to do something on the lines of this
ptrColorData[i].B = &somedata[i];
ptrColorData[i].G = &somedata[i+1];
ptrColorData[i].R = &somedata[i+3];
// this is only called once to initialize. Because the memory address
//is unchanging and somedata changes by functions on its own it means when
// I tell my unreal engine to update a texture by passing (*ptrColorData)
// to a function it automatically has the new data when that function is
// next called.
This should produce the output you want, but be aware. As stated in the comments, the addresses stored int the std::vector<int*> should be considered invalid if you change the size of vector1 or vector2 in any way and if you reorder the elements in the original vectors, your pointers will point to the wrong values. I also removed using namespace std;. See: Why is “using namespace std” considered bad practice?.
#include <iostream>
#include <vector>
// Print function
void PrintVector(std::vector<int> v) {
for(auto x : v) std::cout << x << ", ";
std::cout << "\n";
}
void PrintVector(std::vector<int*> v) {
for(auto x : v) std::cout << *x << ", ";
std::cout << "\n";
}
int main() {
std::vector<int> vector1;
std::vector<int> vector2;
std::vector<int*> ptrvector; // pointers to the elements in vector1/2
//Do some assignment so the vectors have values
for( int i = 1; i<=3; i++) {
vector1.push_back(i);
vector2.push_back(2*i);
}
// Add pointers in ptrvector to the addresses in vector1.
ptrvector.reserve(vector1.size());
for(auto& r : vector1)
ptrvector.emplace_back(&r);
//Print out:
PrintVector(vector1); // (1,2,3)
PrintVector(vector2); // (2,4,6)
PrintVector(ptrvector); // (1,2,3)
ptrvector[0] = &vector2[2];
PrintVector(ptrvector); // (6,2,3);
vector2[2] = 20;
PrintVector(ptrvector); // (20,2,3)
}

c++ right way to initialize a vector of a struct

i searched a lot here, but there is no right explanation for me, for an advanced newbie in c++. I worked before with vector of structs and now I get segmentation faults...
Thats why I want to know how such objects actually works and if it is the right the way I am doing!
I have a struct like
struct numberOfSpecies {
int predator;
int prey1;
int prey2;
};
and a vector of it:
std::vector<numberOfSpecies> size;
Before I resize it and fill it with values.
size.resize(100);
what is actually this doing? Is this right for a struct?
It looks like it is initialized with zeros...
Now I am doing this like:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
Is this right? Where are possible issues? How to do it better?
The easiest and 'correct' solution here is probably to just use the resize() function that belongs to the vector object with aggregate initialization (if you have access to c++11 and on), something like
size.resize(100,{0,0,0}); //aggregate initialization
for(int k = 0; k < N; ++k)
{
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
All members of each numberOfSpecies object will be initialized to 0.
This:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
will write zeros to the tth element of size - that may or may not be useful:
This:
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
will increment the tth element of size N times. This seems incredibly unlikely to be useful. I think what you want is:
size[0].predator=0; // Technically not needed because .resize()
size[0].prey1=0; // will have initialized it to zero anyway
size[0].prey2=0; // *BUT* explicit is always better than implicit.
// Initialize each element of size to be one greater than previous.
for(int k = 1; k < N; ++k){
size[k].predator = size[k-1].predator + 1;
size[k].prey1 = size[k-1].prey1 + 1;
size[k].prey2 = size[k-1].prey2 + 1;;
}
Use the value parameter for static parameters.
#include <vector>
struct foo{
int g;
int h;
int l;
};
int main()
{
std::vector<foo> manyFoo(10, {0});
manyFoo.resize(60, {0});
}
If you want to grow your vector as you also put arbitrary values into the struct you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec;
for (int i=0;i<10;i++) {
lVec.emplace_back(foo(i,i*2,i*4));
}
int lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
If you know the size of the vector and you want to populate it you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec(10,{0,0,0});
int lPos = 0;
for (auto &rFoo: lVec) {
rFoo = foo(lPos,lPos*2,lPos*4);
lPos++;
}
lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
You could add an default constructor to your structure. The new code will look something like this:
struct numberOfSpecies {
numberOfSpecies (): predator(0), prey1(0), prey2(0) { } // default constructor
int predator;
int prey1;
int prey2;
};
That way, your structure will be properly initialized inside your vector when resize is applied.

Operator Overloading

I'm new to C++, this is my first week since the upgrade from fortran. Sorry if this is a simple question, but could someone help me with operator overloading. I have written a program which has two classes. One object contains a vector and two scalars, the other class simply contains the first object. In a test implementation of this code I suspect the operator overloading to be at fault. The program tries to accomplish the following goals:
1) Initialize first structure.
2) Initialize a second structure containing the initialized first structure. After this is imported, the value val0 = 10 is added to every element of the vector in the enclosing structure, structure2.structure1 .
3) Output structure1 and structure2 variables to compare.
For this simple program my output is:
100
100
0
0
0 0 10
1 1 11
2 2 12
3 3 13
...
I was expecting:
100
100
0
10
0 0 10
1 1 11
2 2 12
3 3 13
...
Clearly my overloaded = operator is copying my vector properly, but one of the scalars? Could someone help?
#include <iostream>
using namespace std;
typedef double* doublevec;
// This first class contains a vector, a scalar N representing the size of the vector, and another scalar used for intializing the vector.
typedef class Structure1
{
int N, vec0;
doublevec vec;
public:
// Constructor and copy constructor.
Structure1(int Nin, int vecin) : N(Nin), vec0(vecin) { vec = new double [N]; for(int i = 0; i < N; i++) { vec[i] = i + vec0; } }
Structure1(const Structure1& structurein);
// Accessor functions:
int get_vec0() { return vec0; }
int get_N() { return N; }
doublevec get_vec() { return vec; }
// Overide equivalence operator:
Structure1& operator=(const Structure1& right)
{
//Handle Self-Assignment
if (this == &right) return *this;
N = right.N;
vec0 = right.vec0;
for (int i = 0; i < N; i++)
{
vec[i] = right.vec[i];
}
return *this;
}
// Destructor:
~Structure1() { delete []vec; }
} Structure1;
Structure1::Structure1(const Structure1& structurein)
{
N = structurein.N;
vec = new double[N];
for(int i = 0; i < N; i++)
{
vec[i] = structurein.vec[i];
}
}
// This class just contains the first structure.
typedef class Structure2
{
Structure1 structure;
// Mutator Function:
void mutate_structure();
public:
// Constructor:
Structure2(const Structure1& structurein) : structure(structurein) { mutate_structure(); }
// Accessor Function:
Structure1 get_structure() { return structure; }
// Destructor:
~Structure2() {}
} Structure2;
void Structure2::mutate_structure()
{
int N = structure.get_N();
Structure1 tempstruct(N,10);
structure = tempstruct;
}
int main (int argc, char * const argv[])
{
const int N = 100;
Structure1 structure1(N,0);
Structure2 structure2(structure1);
cout << structure1.get_N() << endl;
cout << structure2.get_structure().get_N() << endl;
cout << structure1.get_vec0() << endl;
cout << structure2.get_structure().get_vec0() << endl;
for(int i = 0; i < N; i++)
{
cout << i << " " << structure1.get_vec()[i] << " " << structure2.get_structure().get_vec()[i] << endl;
}
return 0;
}
it looks like vec0 isn't initialized by your copy constructor...
Try modifying your copy constructor to:
Structure1::Structure1(const Structure1& structurein)
{
N = structurein.N;
vec = new double[N];
for (int i = 0; i < N; i++)
{
vec[i] = structurein.vec[i];
}
// ADD THIS LINE
vec0 = structurein.vec0;
}
Your copy-constructor Structure1::Structure1(const Structure1 &) doesn't copy vec0. It's not getting initialised at all, so gets whatever is in memory.
Also, you might want to check Structure1's operator=. If you assign a large vector to a small vector, then you'll potentially overflow the array in the destination. You might need to reallocate memory in operator=.