Losing references to objects inside containers - c++

I am struggling to fix a piece of code, even though I believe I know the cause. I did search a lot on Stack Overflow and many people had similar issues (and good answers were provided), but still, I am not sure I understand the problem with my code.
I tried giving a smaller example, but the structure I have is not simple by itself. I hope the following is simple enough.
My objective on the excerpt:
Have a vector of points.
Have a vector of segments. (Whose endpoints are reference to points in the vector above)
Have a vector of events. (That keep a reference to the exhisting segments and points)
segment::segment (point &pt1, point&pt2, int i) {
s = &pt1; e = &pt2; ind = i; // point *s, point *e, int ind
}
event::event (segment &s, point &pt, int tp) {
seg = &s; type = tp; p = &pt; //segment *seg, int type, point *p
}
void pre_process (int size, std::vector<point>& pts, std::vector<event>& evts,
std::vector<segment>& segs) {
float x, y;
for (int i = 0; i < size; ++ i) {
std::cin >> x >> y;
pts.push_back({x,y});
}
for (int i = 0; i < size; ++i) {
int j = (i+1)%size;
if (cmpXY(pts[i], pts[j]))
segs.push_back({pts[i], pts[j], i});
else
segs.push_back({pts[j], pts[i], i});
evts.push_back({segs[i], *segs[i].s, 0});
evts.push_back({segs[i], *segs[i].e, 1});
std::cout << 2*i << "\n";
std::cout << segs[i].s << "\n"; //ALWAYS EQUAl
std::cout << evts[2*i].seg->s << "\n";
} // LINE X
for (int i = 0; i < size; ++i) { //LINE Y
std::cout << 2*i << "\n";
std::cout << segs[i].s << "\n"; //DIFFERENT SOMETIMES
std::cout << evts[2*i].seg->s << "\n";
}
So, the problem is that some of addresses my objects are pointing to change from LINE X to LINE Y. In particular, pts and segs remain the same.
From what I know and from what I understood here or here I cannot get the reference to an object on the stack of any function (my for loop, for example). However, I believe the lifetime of the object on the container is the same as the container itself. It makes me believe that all objects I push_back() should persist through the function pre_proccess and the function that is calling it.

push_back on vector (might) invalidate previous reference/iterator.
it happens in the loop there
if (cmpXY(pts[i], pts[j]))
segs.push_back({pts[i], pts[j], i});
else
segs.push_back({pts[j], pts[i], i});
evts.push_back({segs[i], *segs[i].s, 0});
you have to reserve enough place in segs to avoid reallocation (or change the logic).

It looks that the vector resize itself and had to be relocated (which will invalidate all iterator references).
Try to use std::vector::reserve before processing:
void pre_process (int size, std::vector<point>& pts, std::vector<event>& evts,
std::vector<segment>& segs) {
pts.reserve(size);
evts.reserve(size);
segs.reserve(size);
float x, y;
for (int i = 0; i < size; ++ i) {
std::cin >> x >> y;
pts.push_back({x,y});
}
for (int i = 0; i < size; ++i) {
int j = (i+1)%size;
if (cmpXY(pts[i], pts[j]))
segs.push_back({pts[i], pts[j], i});
else
segs.push_back({pts[j], pts[i], i});
evts.push_back({segs[i], *segs[i].s, 0});
evts.push_back({segs[i], *segs[i].e, 1});
std::cout << 2*i << "\n";
std::cout << segs[i].s << "\n"; //ALWAYS EQUAl
std::cout << evts[2*i].seg->s << "\n";
} // LINE X
for (int i = 0; i < size; ++i) { //LINE Y
std::cout << 2*i << "\n";
std::cout << segs[i].s << "\n"; //DIFFERENT SOMETIMES
std::cout << evts[2*i].seg->s << "\n";
}

Related

Findmax() method returns second highest value when first element of array is the highest

This findMax function returns max value from the array only if it is located at some index other than first index. I don't understand why because my findMin function that has almost the same code works perfectly fine.
void findMax(int array[5])
{
maximum = array;
for (i = 0; i < 5; i++)
{
if (*(array+i) > *maximum)
*maximum = *(array+i);
}
cout<<"Maximum element in the array is "<< *maximum << "\n" ;
}
This is my findMin fun that is working fine.
void findMin(int array[5])
{
minimum = array;
for (i = 0; i < 5; i++)
{
if (*(array+i) < *minimum)
*minimum = *(array+i);
}
cout<<"Minimum element in the array is "<< *minimum <<"\n";
}
The other answers have described how to do this more cleanly in C++. But to point out the actual bug: it's in this line.
*maximum = *(array+i);
You're not reassigning the maximum pointer to point to the maximum element, but rather you're never changing the pointer, but changing the value inside the array where maximum points to (i.e. array[0]). You meant this instead:
maximum = array + i;
The same issue is present in your findMin function as well.
First of all, as one of the comments on your question said this is mostly C way of doing things. In C++ you should use std::vector, std::min_element and std::max_element. It's easier and safer to use them instead of doing everything manually by yourself.
But, if you really want to do it yourself, try this code out, it should work:
void findMax(int array[])
{
maximum = array;
for (int i = 1; i < 5; i++)
{
if (*(array + i) > *maximum)
maximum = (array + i);
}
cout << "Maximum element in the array is " << *maximum << "\n";
}
void findMin(int array[])
{
minimum = array;
for (int i = 1; i < 5; i++)
{
if (*(array + i) < *minimum)
minimum = (array + i);
}
cout << "Minimum element in the array is " << *minimum << "\n";
}
This should work assuming that minimum and maximum are globally declared like this:
int * maximum;
int * minimum;
There are minmax_element tools for finding maximum and minimum, this is the most optimal variant of solving your problem - see the definition of the StdMinMax function.
But if you want to implement the logic yourself, I gave an example of a function, see the definition of the MinMax function
#include <iostream>
#include <algorithm>
void StdMinMax(int* arr, const unsigned int size)
{
std::pair<int*, int*> bounds = std::minmax_element(arr, arr + size); // or use auto bounds = ... ore auto [max, min] = ...
std::cout << "min : " << *bounds.first << " max : " << *bounds.second << std::endl;
}
void MinMax(int* arr, const unsigned int size)
{
std::cout << "Find max : " << std::endl;
auto currentMax = *arr;
for (int i = 1 ; i < size; ++i)
{
if (arr[i] > currentMax)
{
currentMax = arr[i];
}
}
std::cout << "Max : " << currentMax << std::endl;
std::cout << "Find min : " << std::endl;
auto currentMin = *arr;
for (int i = 1 ; i < size; ++i)
{
if (arr[i] < currentMax)
{
currentMin = arr[i];
}
}
std::cout << "Min : " << currentMin << std::endl;
}
int main()
{
const unsigned int size{5};
int array[size]{1, 3, 4, -11, 77};
StdMinMax(array, size);
MinMax(array, size);
return 0;
}

why can't I store values in my 2D vector by push back?

I got stuck in many problems where I was trying to store values in 2D vectors.
So I have written this simple code.
I am just storing and printing my values :
int main()
{
vector<vector<int>> vec;
vector<int> row{1,3,5,7,9,12,34,56};
int i,n,m,rs,vs;
rs=row.size();
cout<<"rs = "<<rs<<endl;
for(i=0;i<(rs/2);i++)
{
vec[i].push_back(row.at(i));
vec[i].push_back(row.at(i+4));
}
vs=vec.size();
cout<<vs<<endl;
for(n=0;n<vs;n++)
{
for(m=0;m<2;m++)
{
cout<<vec[n][m]<<" ";
}
cout<<endl;
}
return 0;
}
First you should read Why is “using namespace std;” considered bad practice?.
Declare variables when you use them and not at the beginning of your program.
The vector vec is empty at the beginning. In the loop
for(i=0;i<(rs/2);i++)
{
vec[i].push_back(row.at(i));
vec[i].push_back(row.at(i+4));
}
you are taking a reference to the i-th element in vec with
vec[i]
but this element does not exist. This is undefined behavior and can result in a segmentation fault. You can fix it by constructing the vector with the needed elements
#include <iostream>
#include <vector>
int main()
{
std::vector<int> row{1,3,5,7,9,12,34,56};
int rs = row.size();
std::vector<std::vector<int>> vec(rs / 2);
std::cout << "rs = " << rs << '\n';
for(int i = 0; i < rs / 2; ++i)
{
vec[i].push_back(row.at(i));
vec[i].push_back(row.at(i + 4));
}
int vs = vec.size();
std::cout << vs << '\n';
for(int n = 0; n < vs; ++n)
{
for(int m = 0; m < 2; ++m)
{
std::cout << vec[n][m] << " ";
}
std::cout << '\n';
}
return 0;
}
In this example the line
std::vector<std::vector<int>> vec(rs / 2);
constructs a vector containing rs / 2 default constructed elements. Alternatively you can start with an empty vector and push back elements in the loop
#include <iostream>
#include <vector>
int main()
{
std::vector<int> row{1,3,5,7,9,12,34,56};
int rs=row.size();
std::vector<std::vector<int>> vec;
std::cout << "rs = " << rs << '\n';
for(int i = 0; i < rs / 2; ++i)
{
vec.push_back({row.at(i), row.at(i+4)});
//
// is similar to:
// vec.push_back({});
// vec.back().push_back(row.at(i));
// vec.back().push_back(row.at(i+4));
//
// is similar to:
// vec.push_back({});
// vec[i].push_back(row.at(i));
// vec[i].push_back(row.at(i+4));
}
int vs = vec.size();
std::cout << vs << '\n';
for(int n = 0; n < vs; ++n)
{
for(int m = 0; m < 2; ++m)
{
std::cout << vec[n][m] << " ";
}
std::cout << '\n';
}
return 0;
}
I recommend the first solution. It's better to allocate memory for all elements and work with it instead of allocate memory in each loop iteration.

Find dimensions of a container passed by reference

I wrote a following code:
#include <iostream>
#include <vector>
#include <iomanip>
using std::cin; using std::cout; using std::endl;
int DivideTwoFactorials(int m, int n)
{
int div(1);
while (m > n)
{
div *= m;
m--;
}
return div;
}
int Factorial(int m)
{
int fact(1);
for (int i(1); i <=m; i++) fact *= i;
return fact;
}
int BinomialCoefficient(int m, int n)
{
return (DivideTwoFactorials(m, n) * (1./Factorial(m-n)));
}
template <typename Type>
void Modify3DContainer(Type &a, int fun(int, int), int p = 0, int q = 0)
{
int m(a.size());
int n(a[0].size());
int z(a[0][0].size());
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < z; k++)
{
if (a[i][j][k] == fun(p, q)) a[i][j][k] = a[i][j][k] * a[i][j][k];
}
}
}
}
int main()
{
cout << endl << "Input dimensions of 3D container: ";
int m, n, p;
cin >> m >> n >> p;
std::vector<std::vector<std::vector<int>>> a(m, std::vector<std::vector<int>>(n, std::vector<int>(p)));
cout << endl << "Input elements of 3D container: ";
int x;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cin >> x;
a[i][j][k] = x;
}
}
}
Modify3DContainer(a, BinomialCoefficient, 6, 4);
cout << endl << "Modified 3D container: " << endl << endl;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cout << std::setw(6) << a[i][j][k];
}
cout << endl;
}
cout << endl;
}
return 0;
}
There is one issue regarding the function "Modify3DContainer" which accepts the following parameters:
a reference on a 3D container
a function that returns an int and receives two int parameters
two int parameters with default value 0.
The function is supposed to find all elements in the 3D container that are equal to return value of function defined by the second parameter when that function receives p and q as parameters, and substitute those elements with their square value.
The problem here is that function "Modify3DContainer" accepts multiple types of containers and I am not allowed to pass dimensions of the container to said function (c++ programming assignment). The function currently works only for vector of vectors of vectors by using the size() method, but it will not work for regular arrays. I tried using the sizeof operator, but it doesn't work on multidimensional vectors. Checking the type of the container with typeid could be one possible solution, but there are many combinations to check since the 3D container could, for example, be vector of vectors of deques etc.
So my question is, is there a way to find the size of passed 3D container, no matter its type?
Thank you.
If you really want to know the size then what you are looking for is std::size. It will tell you the size of anything passed to it that is a raw array or an object that has a size member function. Unfortunately it is a C++17 feature so you might not have it available in the compiler you are using.
Fortunately the mechanics for it already exist in the current standard so we can write our own like the possible implementation provided at previous link
template <class C>
constexpr auto size(const C& c) -> decltype(c.size())
{
return c.size();
}
template <class T, std::size_t N>
constexpr auto size(const T (&array)[N]) noexcept
{
return N;
}
And using them in something like
int main()
{
std::vector<std::vector<std::vector<int>>> vec(10, std::vector<std::vector<int>>(20, std::vector<int>(30, 0)));
int arr[10][20][30];
std::cout << size(vec) << "\t" << size(arr) << "\n";
std::cout << size(vec[0]) << "\t" << size(arr[0]) << "\n";
std::cout << size(vec[0][0]) << "\t" << size(arr[0][0]) << "\n";
return 0;
}
We get
10 10
20 20
30 30
Live Example
If you do not need the size but just need to loop then you can use a range based for loop or a regular loop and use std::begin and std::end which works with containers and arrays.

vector subscript out of range when writing to file

I want to write a vector to a file, which represents the outcomes of a function that increments j with steps of "double Golf_dl".
The vector itself must have "int Golf_NL" elements in it. (Golf_dl is a private member of class Tsunami)
The problem is that I get a constant vector with all values equal to 0.5, which is rubbish.
Can someone see what's wrong?
Code:
void T_Tsunami::Toestand(int nl)
{
struct pb
{
std::vector<double>& v_;
pb(std::vector<double>& v)
: v_(v){};
pb& operator+(double i)
{
v_.push_back(i);
return *this;
}
};
for( double i = 0; i < nl; i++ )
{
double j=0;
double y = 0.25*(1-tanh(double(j-75)/5));
j+=Golf_dl;
pb(T_1)+y;
}
}
void T_Tsunami::Write(vector<double>d)
{
const int Naamgrootte=64;
char Naam[Naamgrootte];
std::cout << "Geef een bestandsnaam in" << std::endl;
std::cin >> Naam;
std::cout << std::endl;
std::ofstream outFile(Naam);
if (!outFile)
{
std::cerr << "Kan bestand niet openen" << std::endl;
exit (1);
}
for (int i=0; i<100; i++)
{
outFile << d[i] << std::endl;
}
outFile.close();
}
Your problem is in here:
for( double i = 0; i < nl; i++ )
{
double j=0;
double y = 0.25*(1-tanh(double(j-75)/5));
j+=Golf_dl;
pb(T_1)+y;
}
Consider the fact that the loop variable, i, is not used anywhere inside the loop. Also, j and y do not retain their values between loops (they are not static).

What is the most efficient way to initialize a 3D vector?

I have a 3D string vector in C++:
vector<vector<vector<string>>> some_vector
That I am trying is to find a fast method to allocate memory for it.
I tried to define it with two different methods as follow:
#include<vector>
#include<iostream>
#include<ctime>
using namespace std;
#define DIM1 100
#define DIM2 9
#define DIM3 120
int main()
{
clock_t t1_start = clock();
vector<vector<vector<string>>> vec1(DIM1, vector<vector<string>>(DIM2, vector<string>(DIM3)));
clock_t t1_end = clock();
double diff1 = (t1_end - t1_start) / double(CLOCKS_PER_SEC);
clock_t t2_start = clock();
vector<vector<vector<string>>> vec2;
vec2.resize(DIM1);
for(int i = 0; i < DIM1; i++)
{
vec2[i].resize(DIM2);
for(int j = 0; j < DIM2; j++)
vec2[i][j].resize(DIM3);
}
clock_t t2_end = clock();
double diff2 = (t2_end - t2_start) / double(CLOCKS_PER_SEC);
cout<<"1st definition used time: "<<diff1<<"s"<<endl;
cout<<"2nd definition used time: "<<diff2<<"s"<<endl;
}
I expect that the first method (vec1) could be faster than the 2nd one (vec2).
But it turned out that the 1st method is much slower than the 2nd. On my machine, the 1st method used 0.245 seconds, while the 2nd method used 0.152 seconds.
Moreover, when I switch the data type to int, the 1st one took 0.058 second, and the 2nd took 0.004.
May I know what cause such difference? And is there better way to allocate memory for a 3D vector?
Many thanks in advance.
May I know what cause such difference?
The first version constructs a 2-d vector by copying a 1-d vector, and then constructs the 3-d vector by copying that. This might be slower than resizing the vectors without copying. However, I'd hope that the difference would be negligible if you're building with optimisation.
And is there better way to allocate memory for a 3D vector?
It might be better to use a single contiguous array, wrapped in a class that provides multi-dimensional accessors. This would make allocation much simpler, and would also avoid some pointer dereferencing when accessing elements (at the cost of a bit of arithmetic). Something like this:
template <typename T>
class vector3d {
public:
vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
{}
T & operator()(size_t i, size_t j, size_t k) {
return data[i*d2*d3 + j*d3 + k];
}
T const & operator()(size_t i, size_t j, size_t k) const {
return data[i*d2*d3 + j*d3 + k];
}
private:
size_t d1,d2,d3;
std::vector<T> data;
};
I think I'd optimize it by allocating one large block of memory instead of a lot of little ones. This one is only 2D instead of 3D, but gives the basic idea:
template <class T>
class matrix {
size_t columns_;
std::vector<T> data;
public:
matrix(size_t columns, size_t rows) : columns_(columns), data(columns*rows) {}
T &operator()(size_t column, size_t row) { return data[row*columns_+column]; }
};
For 3D, you'll need to deal with "planes" (or something) along with rows and columns, but the basic idea is pretty much the same.
I added several features to Mike Seymour's code such as dynamically resize the 3d vector and on access/assign bounds checking for data vector.
template <typename T>
class vector3d
{
public:
vector3d(size_t d1=0, size_t d2=0, size_t d3=0, T const & t=T()) :
d1(d1), d2(d2), d3(d3), data(d1*d2*d3, t)
{}
T & operator()(size_t i, size_t j, size_t k)
{
return (i<=d1 && j<=d2 && k<=d3) ? data[i*d2*d3 + j*d3 + k]
: data.at(i*d2*d3 + j*d3 + k);
}
T const & operator()(size_t i, size_t j, size_t k) const
{
return data[i*d2*d3 + j*d3 + k];
}
void resize(const size_t _d1=0, const size_t _d2=0, const size_t _d3=0)
{
data.resize(_d1*_d2*_d3);
d1=_d1;
d2=_d2;
d3=_d3;
}
void shrink_to_fit()
{
data.shrink_to_fit();
}
const size_t length() const
{
return data.size();
}
const size_t capacity() const
{
return data.capacity();
}
const size_t x() const
{
return d1;
}
const size_t y() const
{
return d2;
}
const size_t z() const
{
return d3;
}
private:
size_t d1,d2,d3;
std::vector<T> data;
};
Usage:
vector3d<int> vec3d(2,2,2,31); //create 2x2x2 3d vector and fill it with 31
vec3d(1,1,2)=45; //assign 45 at vec3d(1,1,2)
vec3d.resize(2,2,1); //resize the vec3d to 2x2x1
vec3d(1,2,2)=67; //error (its out of bounds)
To initialize a 3D string vector you shall initialize the vector structure for each dimension one at a time and for each index, for instance:
vector<vector<vector<string> > > myvector; //declare the 3D vector
for(k=0; k<3; k++)
{
myvector.push_back(vector<vector<string> >()); //initialize the first index with a 2D vector
for(i=0; i<4; i++)
{
myvector[k].push_back(vector<string>()); //initialize the 2 index with a row of strings
for(j=0; j<4; j++)
{
result = " whatever you want to insert in the vector element";
myvector[k][i].push_back(result); //fulfill the last index regularly
}
}
}
When you initialize a vector of vectors in the first method, a temporary vector is allocated and then copied into the outer vector the required number of times. This means you have an extra allocation that is unnecessary and the new elements are initialized by copying their value from another data structure, which uses more memory accesses.
Resizing the vectors as per the second method is more ugly but avoids the extra allocation. Furthermore the new elements are created by the default constructor and do not need to copy from other vectors. This will also be faster.
If speed matters (and maybe it doesn't, premature optimization and all that), then you must use the second method (OR a single-block allocation as suggested by the other answers). I don't have faith that a compiler can simply "optimize" away the inefficiency of the first method.
Here is an example of various dimensions of vectors in case anyone out there cares. I know when I was starting out it was a pain to find how to give initial values to multidimension vectors as I couldn't find any examples;
// This simple project demonstrates a single vector, a 2D vector, a 3D vector and a 4D vector in C++
//
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> myVector = { 0,1,2,3,4,5,6 };
vector<vector<int>> my2dVector = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25},{0,-1,-2,-3,-4},{-6,7,22,-15,-25},{true,true,false,true,false} };
vector < vector < vector<int>>> my3dVector =
{
{
{1,2,3},
{4,5,6}, // plane 0
{7,8,9}
},
{
{-1,-2,-3},
{-4,-5,-6}, // plane 1
{-10,-22,36}
},
{
{129,212,999},
{0,0,1}, // plane 2
{false,true,false}
}
};
vector<vector<vector<vector<int>>>> my4dVector =
{
{ //Cube 0
{
{1,2,3},
{4,5,6}, // plane 0
{7,8,9}
},
{
{-1,-2,-3},
{-4,-5,-6}, // plane 1
{-10,-22,36}
},
{
{129,212,999},
{0,0,1}, // plane 2
{false,true,false}
}
},
{ //Cube 1
{
{10,2,-9},
{44,55,60}, // plane 0
{71,85,99}
},
{
{-561,-6562,-453},
{-14,-55,-76}, // plane 1
{-110,-212,316}
},
{
{729,812,456},
{40,10,17}, // plane 2
{true,true,false}
}
}
};
// 1D VECTOR..............
cout << "This is a 1D vector of size " << myVector.size () << "\n";
for (int i = 0; i < myVector.size (); i++)
{
cout << myVector[i] << "\t";
}
cout << "\n\n";
// 2D VECTOR..............
cout << "This is a 2D vector of size " << my2dVector.size () << " X " << my2dVector[0].size () << ".";
if (my2dVector.size () == my2dVector[0].size ()) cout << " This is a square matrix.";
cout << "\n ";
for (int i = 0; i < my2dVector[0].size (); i++)
{
cout << "C" << i << "\t";
}
cout << endl;
for (int i = 0; i < my2dVector.size (); i++)
{
cout << "Row: " << i << " -> ";
for (int j = 0; j < my2dVector[i].size (); j++)
{
if (my2dVector[i][j] >= 0 && my2dVector[i][j] <= 9) cout << " ";
cout << my2dVector[i][j] << "\t";
}
cout << endl;
}
cout << "\n\n";
// 3D VECTOR.................
cout << "This is a 3D vector of size " << my3dVector[0].size () << " X " << my3dVector[0][0].size () << " with " << my3dVector.size () << " planes.\n";
for (int i = 0; i < my3dVector.size (); i++)
{
cout << "Plane #" << i << "\n";
for (int j = 0; j < my3dVector[i].size (); j++)
{
for (int k = 0; k < my3dVector[i][j].size (); k++)
{
cout << my3dVector[i][j][k] << "\t";
}
cout << "\n";
}
}
cout << "\n\n";
//4D VECTOR.................
cout << "This is a 4D vector of size " << my4dVector[0][0].size () << " X " << my4dVector[0][0][0].size () << " with " << my4dVector[0].size () << " planes and " << my4dVector.size () << " cubes.\n";
for (int i = 0; i < my4dVector.size (); i++)
{
cout << "\nCUBE #"<< i<< " _________________\n";
for (int j = 0; j < my4dVector[i].size (); j++)
{
cout << "Plane #" << j << " |\n";
for (int k = 0; k < my4dVector[i][j].size (); k++)
{
for (int l = 0; l < my4dVector[i][j][k].size (); l++)
{
cout << my4dVector[i][j][k][l] << "\t";
}
cout << "|\n";
}
cout << "________________________|\n";
}
cout << "\n";
}
}