Value of vector of structures changes unexpectedly - c++

I have a strange problem. There is a vector of structures. With a temporary structure, I push_back to that vector of structures. But when I check the first member's cnt, I see that it became changed. Any idea? (Below code is a simplified version but a representative one)
struct Vector
{
float *dim;
Vector ()
{
dim = new float [3];
}
};
struct Face
{
float an_N, an_P;
int P, N;
Vector Af;
float Ad;
Vector cnt;
float ifac;
float mf;
};
std::vector <Face> face;
Face temp_face;
for (;;)
{
temp_face.cnt.dim[0] = 0.f;
temp_face.cnt.dim[1] = 0.f;
temp_face.cnt.dim[2] = 0.f;
for (int q=0; q<n_vtx_2D; ++q)
{
temp_face.cnt = temp_face.cnt + pt[vtx[q]] / n_vtx_2D;
}
face.push_back(temp_face);
}
std::cout << face[0].cnt.dim[0] << std::endl;
Output
0.25
0

The default compiler generated copy constructor (and assignment operator) is being used for Vector and Face (but most importantly Vector). As the code re-uses the same instance of Face, named temp_face, all the instances of Face in the vector face point to the same Face.cnt.dim array (as the faces will contain copies of temp_face).
I can't see any reason for dynamically allocated the array inside Vector as it is a fixed size. Suggest changing to:
struct Vector
{
float dim[3];
};
Or you need to implement copy constructor, assignment operator and destructor for Vector.
See What is The Rule of Three? for more information.

Related

Best way for copying large container in c++

I am interested in the best way regarding performance of copying large containers. Imagine that one has a vector container that stores for example 60.000.000 entries (probably long doubles) or much more values. Now, if one is solving, for example, an ODE (ordinary differential equation), it is necessary (based on the algorithm in use) to make a copy of the old values which are used for the calculation to update the new values. Following (imaginary) example:
// This container is inside a class (so it is initialized and stored at the memory during runtime)
vector<long double> Y(60000000,0);
// Later on in a function
void solve()
{
for(i=0; i<iMax, ++i)
{
// Make a copy for the field one is solving for (depending on the algorithm in use if it is needed)
// The following is not the best solution as we allocate and deallocate YprefIter for each
// Iteration; imagine iMax = 1000000
vector<long double> YprefIter = Y;
...
// Do some analysis (simplified);
Y = something * YprefIter * something + anything
// As YprefIter might be used somewhere else, we cannot update Y only
Y = YprefIter + Y * whatever
...
}
}
Sure, while taking the vector<long double> YprefIter before the brackets, we do not have to create and destroy the object for each iteration. This should be definitely a better choice:
// This container is inside a class (so it is initialized and kept)
vector<long double> Y(60000000,0);
// Later on in a function
void solve()
{
vector<long double> YprefIter (Y.size(), 0);
for(i=0; i<iMax, ++i)
{
// Make a copy for the iteration algorithm
// Better solution as we get rid of the memory allocation and deallocation
YprefIter = Y;
...
}
}
However, I am asking myself, if there are more advanced solutions around. Such as using the move semantics in such an example or do other things that I am not aware of stuff which would be much better in the sense of using actual developments. I would expect that my above-mentioned strategies are not state of the art. It just came into my mind that I could use two pointers while switching the pointing object for each iteration. However this is just a thought, did not test my logic here but the idea is that I do not need to copy anything; maybe a better solution and if such things work, I am sure there is already something implemented in c++ :)
// This container is inside a class (so it is initialized and kept)
vector<long double> Y(60000000,0);
// Later on in a function
void solve()
{
// Create the second object
vector<long double> YprefIter (Y.size(), 0);
// Pointer 1 and Pointer 2
vector<long double>* pToY = NULL;
vector<long double>* pToYPref = NULL
// Set pointer pToY to point to Y
pToY = &Y;
for(i=0; i<iMax, ++i)
{
// Switch the Pointer fields for each iteration
if (i%2)
{
pToY = &Y;
pToYPrefIter = &YPrefIter;
}
else
{
pToY = &YPrefIter;
pToYPrefIter = &Y;
}
// Work with the pointers afterwards
...
}
}
Any comment is appreciated. Tobi
The first snippet is basically something like this
for(i=0; i<iMax, ++i)
{
vector<long double> YprefIter = Y;
// ...
Y = f(YprefIter);
// ...
}
In this case, you could simply swap the two vectors:
// Initialize Y_old
vector<long double> Y_old = whatever(),
Y;
for(i=0; i<iMax, ++i)
{
// ...
Y = f(Y_old);
// ...
// The swap is implemented in terms of moves, it doesn't copy the values.
std::swap(Y_old, Y);
}

Choose at runtime array or vector in C++

I have a problem described as below ::
class datad {
private:
int *a;
int _size;
vector<int> v;
public:
datad(int arr[], int size) {
_size = size;
for (int i = 0; i < size; i++)
a[i] = arr[i];
}
datad(vector<int> ve)
{
v = ve;
_size = ve.size();
}
void printdata()
{
// print data which the object has been initialized with
// if object is initialized with vector then print vector
// array print array
}
};
int main()
{
// print only vector data
int a[] = { 9,4,8,3,1,6,5 };
datad d(v1);
d.printdata();
// print only array data
datad d1(a, 7);
d1.printdata();
}
I need to find the way the object is initialized and then based on the same should be able to printdata accrodingly.
Can someone help me understand if it is possible at all?
Add a bool usesVector to your class and set it to true or false in each constructor as appropriate. Then, in printdata, simply check the value of the boolean.
Or you can set size to -1 in the vector case (as it's otherwise unused) and just check for that.
By the way, your array implementation is broken, because you never allocate any memory for it. You'd be much better off using only the vector version. You can still initialise that vector from array data if you wish.
You can set a flag in respective constructor and check that flag during the printing method.
I hope this is for learning purposes, otherwise as noted you maybe better of using just the vector version. When using dynamic memory management in class you need to be aware of things like rule of three and I guess there is also rule of five.

Unwanted value changes in 1D and 2D arrays returning a value from a function in c++ code

I have a multi-file program that reads data from a file and stores the values in various arrays. The size of the arrays is not known during the compiling. After the values are stored, I use another function to determine the maximum and minimum of each array and return the max/min. Before the "return maximum" statement, the values in the array are correct. After "return maximum", the values are changed or erased.
Here is some of the code including one of the 2D arrays and one of the 1D arrays (there are a few more of those but I removed them so there's less code for you to look at)
**EDITED:
FunctionValues.h: ** removed destructor block
class FunctionValues
{
//define variables, set up arrays of unknown size
public:
float **xvel;
int *imax;
int vessels;
int tot_gridpt;
public:
//Constructor -- initialization of an object performed here
FunctionValues(): xvel(NULL), imax(NULL) {}
//Destructor
~FunctionValues() {
}
void read_function(string filename);
};
FunctionValues.cpp: (this reads a file with some imax values, vessel numbers and velocities and stores them in the appropriate arrays, the other includes are also there) All the arrays made are stored in FunctionValues myval object
#include "FunctionValues.h"
using namespace std;
void FunctionValues::read_function(string filename)
{
std::ifstream myfile(filename.c_str());
//acquire variables
myfile >> vessels; //number of vessels
imax = new int[vessels];
//... code reading the file and storing them, then imax and some other values are multiplied to get int tot_gridpt
xvel = new float *[vessels];
for (int i = 0; i < vessels; i++)
{
xvel[i] = new float[tot_gridpt];
}
//arrays filled
for (int i = 0; i < limiter; i++)
{
myfile >> xvel[count][i];
}
}
Gridpts.cpp: ** range() arguments and parameters
#include "FunctionValues.h"
#include "Gridpts.h"
using namespace std;
// forward declarations
float range(float **velocities, const FunctionValues *myval, int num);
void Gridpts::create_grid(FunctionValues *myval, int ptsnum)
{
//find range, 1 for max, 0 for min from smooth wall simulation results rounded to the nearest integer
float maximum = range(myval->xvel, &myval, 1);
float minimum = range(myval->xvel, &myval, 0);
}
range.cpp: ** arguments changed to pass by pointer
float range(float **velocities, const FunctionValues *myval, int num)
{
if (num == 1)
{
float maximum = 0;
for (int round = 0; round < myval->vessels; round++)
{
for (int count = 0; count < myval->tot_gridpt; count++)
{
if (velocities[round][count] > maximum)
{
maximum = velocities[round][count];
}
}
}
maximum = ceil(maximum);
return maximum;
}
main.cpp:
corner_pts.create_grid(&myval, ptsnum);
This is where the error occurs. cout << "CHECKPOINT: " << myval.xvel[0][0] before "return maximum;" gives -0.39032 which is correct. After "return maximum", causes nothing to be printed and then the program crashes when trying run range() again using the xvel array. Similarly for myval.imax[0].
I apologize for copying in so much code. I tried to only include the essential to what is happening with the array. I have only started programming for about a month so I'm sure this is not the most efficient way to write code but I would greatly appreciate any insight as to why the arrays are being changed after returning a float. Thank you in advance for your time. (And if I have broken any rule about posting format, please let me know!)
So your program crashes when you call range() the second time. Therefore, your issue is most likely there.
Your program is crashing because you are taking your FunctionValues parameter by value, which is then destroyed at the end of the scope of the function, since it is local to the function.
// issue with myval being taken as a copy
float range(float **velocities, FunctionValues myval, int num)
{
//...
} // destructor for local function arguments are called, including myval's destructor
Explanation
Your function parameter FunctionValues myval is taken by copy. Since you have no copy constructor defined, this means that the default copy behavior is used. The default copy behavior simply copies the object data from the supplied argument at the call site.
For pointers, since they hold addresses, this means that you are copying the addresses of those pointers into an object local to the range() function.\
Since myval is local to the range() function, its destructor is called at the end of the scope of the function. You are left with dangling pointers; pointers holding the memory addresses of memory that you have already given back to the free store.
Simplified example of your error:
#include <iostream>
class X
{
public:
X() : p{ new int{ 0 } }
{
}
~X()
{
std::cout << "Deleting!" << std::endl; // A
delete p; // B
}
private:
int* p;
};
void func(X param_by_value) // C
{
// ...
}
int main()
{
X x; // D
func(x); // E
func(x); // F
}
You have variable x (D). You use it to call the function func() (E).
func() takes a parameter of type X by value, for which the variable name is param_by_value (C).
The data of x is copied onto param_by_value. Since param_by_value is local to func(), its destructor is called at the end of func().
Both x and param_by_value have an int* data member called p that holds the same address, because of 3..
When param_by_value's destructor is called, we call delete on param_by_value's p (B), but x's p still holds the address that was deleted.
You call func() again, this time the same steps are repeated. x is copied onto param_by_value. However, this time around, you try to use memory that has been given back to the free store (by calling delete on the address) and (luckily) get an error. Worse yet, when main() exits, it will attempt to call x's destructor again.
You need to do some research into function parameters in C++. Passing by value, passing by reference, passing by pointer, and all of those combined with const.
As user #MichaelBurr points out, you should also look up the rule of three (and rule of five).
I'm just wondering why you opted not to use functionality like std::max/min_element in and std::valarray/vector to allocate a contiguous chunk of memory?
Worse case scenario, if you're a fan of the explicit nature of 2d arrays x[a][b] you could create a basic matrix:
template <typename T>
class Matrix {
public:
Matrix(std::valarray<int>& dims) : dims(dims) {}
Matrix(std::valarray<int>& dims, std::valarray<T>& data) : dims(dims), data(data) {}
std::Matrix<T> Matrix::operator[](int i) {
auto newDims = std::valarray<int>(dims[1], dims.size() - 1);
auto stride = std::accumulate(std::begin(newDims), std::begin(newDims) + newDims.size(), 1, [](int a, int b){ return a * b; })
auto newData = std::valarray<T>(data[i * stride], data.size() - (i * stride));
return Matrix<T>(newDims, newData);
}
protected:
std::valarray<T> data;
std::valarray<int> dims;
}
I think more reliance on the standard libraries for their correctness will likely solve any memory access/integrity issues.

pointers to a class in dynamically allocated boost multi_array, not compiling

I am pretty new to C++ with Boost.
I want an object of class "world" to have an array named "chunk" of type "octreenode". Previously I had an ordinary one-dimensional array, and this worked fine. Now I'm trying to move to using a 3D array with Boost's multi_array functionality, and I'm really not sure what I'm doing wrong.
Simplified code:
class world {
public:
typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks
typedef planetchunkarray::index index;
planetchunkarray *chunk;
world(double x,double y,double z,
int widtheast, int widthnorth, int height) :
originx(x), originy(y), originz(z),
chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height) {
chunk = new planetchunkarray(boost::extents[chunksnorth][chunkseast][chunksup]);
planetchunkarray::extent_gen extents;
for (int cz = 0; cz < chunksnorth; ++cz) {
for (int cx = 0; cx < chunkseast; ++cx) {
for (int cy = 0; cy < chunksup; ++cy) {
(*chunk)[cz][cx][cy] = new octreenode(1,72);
}
}
}
}
};
After which if I attempt to make the assignment
root->planet[0]->chunk[0][0][0]->material = 4;
I get the error:
error: base operand of '->' has non-pointer type 'boost::detail::multi_array::sub_array<octreenode, 1u>'|
"octreenode" has the relevant constructor, and this line worked in identical syntax when it was just:
root->planet[0]->chunk[0]->material = 4;
(with a one-dimensional array). Similarly, while it compiled fine with a one-dimensional array, trying to pass the chunk to functions that expect a pointer to an "octreenode" object, such as:
compactoctree(root->planet[p]->chunk[cz][cx][cy], 0, 14);
generates the error
error: cannot convert 'boost::detail::multi_array::sub_array<octreenode, 1u>' to 'octreenode*' for argument '1' to 'short int compactoctree(octreenode*, int, int)'|
Would be very grateful for any suggestions, I'm sure I'm missing something obvious.
Your array is of value type (octreenode), not pointer type (octreenode*)
Therefore you are not supposed to try to assign a pointer to a dynamically allocated octreenode (new is for heap allocation, by default).
Instead, just assign a value:
(*chunk)[cz][cx][cy] = octreenode(1,72);
In fact, there's no reason to use new on the multi array in the first place either:
UPDATE
In the comments it has been raised that more things could be optimized and that you consider that useful additions to the answer about the compilation error.
So here goes: if you indeed want to initialize all array elements with the exact same value,
You can make the loops way more efficient by forgetting about the array shapes for a moment:
std::fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72});
If you know octreenode is a POD type, you could write
std::uninitialzed_fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72});
but a smart library implementation would end up calling fill_n anyways (because there's no gain). You can use uninitialized_fill_n if octreenode is not a POD type, but it is trivially destructible.
In fact, there's no reason to use new on the multi array in the first place either. You can just use the constructor initialization list to construct the multi_array member
Live On Coliru
#include <boost/multi_array.hpp>
#include <type_traits>
struct octreenode { int a; int b; };
class world {
public:
world(double x, double y, double z, int widtheast, int widthnorth, int height)
:
originx(x), originy(y), originz(z),
chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height),
chunk(boost::extents[chunksnorth][chunkseast][chunksup])
{
octreenode v = { 1, 72 };
std::fill_n(chunk.data(), chunk.num_elements(), v);
}
private:
double originx, originy, originz;
int chunkseast, chunksnorth, chunksup;
typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks
typedef planetchunkarray::index index;
planetchunkarray chunk;
};
int main() {
world w(1,2,3,4,5,6);
}

How to solve the error "expression must be a modifiable lvalue" in c++?

const int ADJ_MATRIX[VERTEX_NUM][VERTEX_NUM]={
{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}
};
typedef struct {
int vertex;
int matrix[VERTEX_NUM][VERTEX_NUM];
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX;
}
The error occurs in this sentence:
graph->matrix = ADJ_MATRIX;
I am new to c++. please tell me why this problem occur and how to solve it?
I want to assign ADJ_MATRIX to the matrix in struct.
As was said, you can't assign arrays in C++. This is due to the compiler being a meanie, because the compiler can. It just won't let you do it...
... unless you trick it ;)
template <typename T, int N>
struct square_matrix {
T data[N][N];
};
square_matrix<int, 10> a;
square_matrix<int, 10> b;
a = b; // fine, and actually assigns the .data arrays
a.data = b.data; // not allowed, compiler won't let you assign arrays
The catch? Now the code needs some little things:
const square_matrix<int, VERTEX_NUM> ADJ_MATRIX={{
// blah blah
}}; // extra set of braces
typedef struct {
int vertex;
square_matrix<int, VERTEX_NUM> matrix;
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX; // no change
}
And to access the cells, now we need to use graph->matrix.data[1][2]. This can be mitigated by overloading operator[] or operator() for square_matrix. However, this is now getting terribly close to the new std::array class, or the Boost equivalent boost::array, so it might be wise to consider those instead.
Unfortunately (or maybe fortunately, who knows...) you can't just assign one array to another in C++.
If you want to copy an array, you will need to either copy each of it's elements into a new array one by one, or use the memcpy() function:
for( int i = 0; i < VERTEX_NUM; i++ )
for( int j = 0; j < VERTEX_NUM; j++ )
graph->matrix[i][j] = ADJ_MATRIX[i][j];
or
memcpy( graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int) );
Arrays are not assignable. You can use memcpy:
memcpy(graph->matrix, ADJ_MATRIX, sizeof(graph->matrix));
You cannot assign an array to another array. You will need to copy the elements from the source to the destination index by index, or use memcpy to copy the data. Array assignment like this is not allowed
You are trying to assign your variable address of a constant data,
try using
memcpy(graph->matrix,ADJ_MATRIX,sizeof(ADJ_MATRIX));//using sizeof(graph->matrix) is safer.
You can't use an array in assignments. You may use cycles or memcpy instead
memcpy(graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int));
or
for(int i = 0; i < VERTEX_NUM; ++i){
for(int j = 0; j < VERTEX_NUM; ++j){
graph->matrix[i][j] = ADJ_MATRIX[i][j];
}
}
The error is thrown, because int matrix[VERTEX_NUM][VERTEX_NUM] in a structure definition means that each structure will have a 2D array of integers of the predefined size and matrix is going to be pointing to its first element. The thing is that matrix cannot be assigned to an arbitrary address, because it's a const pointer i.e. its value (the address it's pointing to) cannot change.
You have 2 options here: you can either use memcpy or some stl algorithms to copy the ADJ_MATRIX into matrix directly or you can declare matrix as a pointer and do the assignment that is currently produces an error.
The latter can be done in the following way:
typedef struct {
int vertex;
const int (*matrix)[VERTEX_NUM];
int vNum;
int eNum;
}Graph;
Thus you can do graph->matrix = ADJ_MATRIX assignment, but you won't be able to modify the individual items in matrix due to constness. This means, graph->matrix[0][1] = 3; is not allowed, while you can read the elements freely.