Scope of struct object in c++ created without new keyword - c++

Coming from a Java background, following code is confusing me. Confusion here is C++ object creation without new keyword. I am creating this object Student_info info; and then adding it to a vector. Since I am not creating it using new keyword, will it be allocated on stack and be destroyed after the loop exits? If that is the case, how the last loop is able to extract the info from vector correctly? Shouldn't it throw exception as all the object added to the vector has been destroyed?
struct Student_info {
string name;
vector<double> marks;
};
int main()
{
int num = 2;
vector<Student_info> student_infos;
for (int i = 0; i < 3; i++) {
Student_info info; //will this object be destroyed once this loop exits?
cout << "Enter name:";
cin >> info.name;
double x;
cout << "Enter 2 marks";
for (int j = 0; j < num; j++) {
cin >> x;
info.marks.push_back(x);
}
student_infos.push_back(info);
}
for (int i = 0; i < 3; i++) {
cout << student_infos[i].name;
for (int j = 0; j < num; j++) {
cout << student_infos[i].marks[j];
}
cout << endl;
}
return 0;
}

You are correct in that the info object will be destroyed, but it is copied into the vector when using push_back. The rest of the code reads the copy from the vector and not the original object.
http://www.cplusplus.com/reference/vector/vector/push_back/
The copying is done using the object's copy constructor which in this case is compiler-provided. It will in turn call the copy constructors on the string and vector members of the struct.

The scope of variable info is the block scope of the for statement starting from the point of declaration of the variable.
for (int i = 0; i < 3; i++) {
Student_info info; //will this object be destroyed once this loop exits?
//...
}
Each time a new iteration of the loop is executed a new object with name info is created.
The scope of variable student_infos is the outer most block scope of function main where the variable is declared.
int main()
{
vector<Student_info> student_infos;
//...
}
When the loop is executed a new object is added to the vector that is a copy of variable info. The vector does not contain a reference to the original object with name info. It creates a copy of the object and stores it within itself internally.
Take into account that in general these loops
for (int i = 0; i < 3; i++) {
cout << student_infos[i].name;
for (int j = 0; j < num; j++) {
cout << student_infos[i].marks[j];
}
cout << endl;
}
are unsafe. It is much better to rely on the actual number of elements in the vectors. You could write instead
for ( vector<Student_info>::size_type i = 0; i < student_infos.size(); i++)
{
cout << student_infos[i].name;
for ( vector<double>::size_type j = 0; j < student_infos[i].marks.size(); j++)
{
cout << student_infos[i].marks[j];
}
cout << endl;
}

Yes, info will be destroyed at the end of the loop. push_back creates a new copy from info, so even if info is destroyed, its copy still exist in the vector.

It will copy the temp Student_info info to the student_infos when push_back is done. If you can write a custom copy constructor for Student_info and print something there you will see the copy construct will invoked.
Consider using,
http://en.cppreference.com/w/cpp/container/vector/emplace_back

Related

Garbage value when trying to remove value from dynamic array

i keep getting garbage value on one of the indexes in the dynamic array when i try to remove a value which was entered by user from a list of elements in the dynamic array.
used pointer as function parameters and replaced the value to be removed with 0 and by using a counter and for loop tried to skip all the 0s but in place of zero theres a garbage value.
#include<iostream>
#include<fstream>
using namespace std;
int size = 0;
int final = 0;
int* read(ifstream& a){
int temp;
a.open("data(1).txt");
while (!a.eof()){
a >> temp;
size++;
}
a.close();
a.open("data(1).txt");
int* arr = new int[size];
for (int i = 0; i < size; i++)
a >> arr[i];
return arr;
}
int* remove(int* a,int search){
for (int i = 0; i < size; i++){
if (a[i] == search)
a[i] = 0;
else final++;
}
int* change = new int[final+1];
for (int i = 0; i < size; i++){
if (a[i] > 0){
change[i] = a[i];
}
else continue;
}
delete[] a;
a = nullptr;
return change;
}
int main(){
int* ptr = nullptr;
int num;
cout << "please enter the number to remove: ";
cin >> num;
ifstream in;
ptr=read(in);
ptr=remove(ptr, num);
for (int i = 0; i < final; i++)
cout << ptr[i] << " ";
cout<<endl;
system("pause");
return 0;
}
There is much to discuss and critize about your code. Also your question is very unclear because we do not have your input file, nor do you tell us what the code should actually do. However, I will leave all "please write actual c++ rather than c without classes" aside and just point you to the one critical mistake:
This loop
int* change = new int[final+1];
for (int i = 0; i < size; i++){
if (a[i] > 0){
change[i] = a[i];
}
else continue;
}
And then this loop
for (int i = 0; i < final; i++)
cout << ptr[i] << " ";
It seems like you want to copy all elements that are >0 to change. Or maybe you want to copy all, its really hard to tell, because broken code is just broken, it does not explain itself. Anyhow...
The first loop leaves all elements change[i] where a[i] <= 0 uninitialized. The values at those indices i are indeterminate. There isn't really a value you can read. Attempting to read an indeterminate value results in undefined behavior.
You are attempting to read all elements of change, but some of them are not initialized, they are indeterminate values. Hence your code has undefined behavior.
There are other situations the will bring your code into bad states, like for example search not begin found in the input array or a[i] > 0 for some i > final. Though, I don't see a possiblity for any input to your code that would not eventually invoke undefined behavior.
You sould use a debugger to see where your code is doing something unexpected.

2D Array of pointers to structs. Memory access issue

I am attempting to write a program to compute the Hungarian method for a set of Jobs:Workers.
I know how I am going to code the bulk of the program, but I am stuck at loading my matrix.
I have created a class to store info in, and I have created a 2d array of pointers to objects of this class. Each entry of the matrix should hold a cost value assigned to that Worker:Job combo.
Every time I try to load the costs into the objects within the array, I keep getting a memory access violation, and I can't figure out why. Any help would be greatly appreciated.
Thanks,
Chris
using namespace std;
class costPtr{
int cost;
int fillRow;
int fillColumn;
public:
costPtr()
{
int fillRow = 0;
int fillColumn = 0;
cost = 0;
}
void fillCost(int costInput)
{
cost = costInput;
}
int printCost() const
{
return cost;
}
};
void fillMatrix(costPtr*** matrix, int workers, int jobs);
void methodMain();
void printMatrix(costPtr*** matrix, int workers, int jobs);
int main()
{
methodMain();
}
void methodMain()
{
int jobs, workers;
cout << "How many jobs are there: ";
cin >> jobs;
cout << "How many workers are there: ";
cin >> workers;
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr*[jobs];
fillMatrix(matrix, workers, jobs);
printMatrix(matrix, workers, jobs);
}
void fillMatrix(costPtr*** matrix, int workers, int jobs)
{
int cost;
for (int i = 0; i < workers; i++)
{
for (int j = 0; j < jobs; j++)
{
cout << "What is the cost for worker " << i + 1 << " doing job " << j + 1 << ": ";
cin >> cost;
(matrix[i][j])->fillCost(cost);
cout << endl;
}
}
}
void printMatrix(costPtr*** matrix, int workers, int jobs)
{
cout << endl << endl;
for (int i = 0; i < workers; i++)
{
for (int j = 0; j < jobs; j++)
cout << (matrix[i][j])->printCost() << " ";
cout << endl;
}
}
The specific cause of the error is here:
(matrix[i][j])->fillCost(cost);
You have declared the pointer, but then you give a command to the object that the pointer points to-- which does not exist. You never constructed it.
The deeper problem is that you attempted this with an array of arrays of pointers, before you tried it with a pointer. When you write code, you should start with something small and simple that works perfectly, then add complexity a little at a time, testing at every step. (For some reason, this rule never comes up in programming courses.)
If you want it to be a "2d" matrix, it should be costPtr** matrix.
// An array of pointers
costPtr** matrix = new costPtr*[workers];
// Each element in the array is (a pointer to) another array
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr[jobs];
Of course, there are always the standard containers like std::vector. You can have a vector of vectors:
// Create and initialize a workers x jobs matrix
std::vector<std::vector<costPtr>> matrix(workers, vector<costPtr>(jobs));
matrix[2][3].printCost(); // Example usage
No explicit memory allocations or pointers.
Edit: After re-reading I see you wanted a "2d array of pointers" so costPtr*** matrix is correct, but you need one more step:
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++) {
matrix[i] = new costPtr*[jobs];
for (int j = 0; j < jobs; j++) {
matrix[i][j] = new costPtr;
}
}
Take a look at the dynamic allocation of you matrix container. To reach your goal, every "star" in the container type must have a "new".
You successfully dealt with the first 2 pointers, like so:
costPtr*** matrix = new costPtr**[workers];
for (int i = 0; i < workers; i++)
matrix[i] = new costPtr*[jobs];
Now all you need to do is deal with the third pointer:
for (int i =0; i < workers; i++)
for (int j = 0; j < jobs; j++)
matrix [i][j] = new costPtr;
Without the last pointer allocation, all elements would point to a null.

Deleting Arrays With Pointers--Multidimensional and Multipointer---in C++

So I know multiple dimensions/arrays can get confusing, but how do I delete these types of arrays properly? I know the syntax, but adding multiple dimensions/pointers gets tricky. Here's some snippet code:
//FIRST PROBLEM
//function to add an item to a pointer array
//due to problems in adding something directly, I created a temp
//temp is not necessary if there's a way without it
int y = 6;
int x = 5;
int *myList = new int[x];
void List::add(int newInt)
{
void List::add(int newInt){
int *temp = new int[x+1];
temp = myList;
temp[x+1] = newInt;
delete [] myList;
int *myList = temp;
}
//SECOND PROBLEM----tricky multidimensional
// not getting any errors, but not sure if done properly
int x;
int y;
int** myMatrix;
cout << "How many rows?" << endl;
cin >> x;
myMatrix = new int*[x];
cout << "How many columns?" << endl;
cin >> y;
for (int i=0; i<x; i++)
myMatrix[i] = new int[y];
for(int i=0; i<10; ++i){
for(int j=0; j<10; ++j){
myMatrix[i][j] = rand();
}
for(int i = 0 ; i < x ; ++i)
{
for(int j = 0 ; j < col ; ++j){
// delete[] myMatrix[i][j]; (tried this method, did not work)
}
delete[] myMatrix[i];
}
delete[] myMatrix;
//looked around for examples, but were all different enough to not help
//
// delete[] myMatrix[i][j]; (tried this method, did not work)
The code you have here
myMatrix[i][j] = rand();
doesn't allocate any new heap memory for myMatrix[i][j] (which is of a non pointer type, but a simple int BTW), but just assigns the result of rand() as a value there.
Thus it's not necessary/wrong, you ever call delete for it.
You only call delete/delete[] as counterparts of new/new[] in the reverse order as they were allocated.
Further, to get redeemed from struggling with memory management, I'd seriously recommend using a c++ standard container like std::vector<std::vector<int>> myMatrix; instead of managing raw pointers.

Destructor causes the program to crash

I am really struggling with the concept of using destructors with copy constructors. If I don't use a destructor the code works fine, as it does it automatically. If I do, I get an error saying 'Debug Assertion Failed!' and 'Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse).
But I want to be able to understand how to use destructors. Here is the code below, I would very much appreciate help explaining what I have done incorrectly or need to do!
class Matrix {
private:
int M;
int N;
double *data;
public:
Matrix();
int getM() const { return M; }
int getN() const { return N; }
//CONSTRUCTOR
Matrix(int sizeR, int sizeC,double * input_data)
{
M = sizeR; //Rows
N = sizeC; //Columns
data = new double[M*N]; //creation of 1D array, uses m&n values
cout << "\nMatrix::Matrix(int sizeR, int sizeC, double * data_value) is invoked...\n\n";
//ENTER DATA INTO MATRIX HERE:
for(int i=0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to
data[i] = input_data[i];//Accesses each value at specific location, inputs value 'val'
for(int i = 0; i < M*N; i++) //Loops for every data entry into 1D array, uses r&c as referenece to size
cout << data[i] << " ";
}
//get function uses row and column from user
double get(int i, int j)
{
return data[i*N+j];
}
double set(int i, int j, double val)
{
data[i*N+j] = val;
cout << "\n\nNEW MATRIX: ";
for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size
cout << data[i] << " ";
return val;
}
Matrix(const Matrix& oldMatrix)
{
cout¸<< "\nMatrix::Matrix(const Matrix&) is invoked....";
M = oldMatrix.getM();
N = oldMatrix.getN();
data = oldMatrix.data;
cout << "\n\n";
//ENTER DATA INTO MATRIX HERE:
for(int i = 0; i < M*N; i++)//Loops for every data entry into 1D array, uses r&c as referenece to size
cout << data[i] << " ";
}
//DESTRUCTOR
~Matrix()
{
//delete data
delete [] data;
data = NULL;
cout << "\n\nMatrix::~Matrix() is invoked...\n\n";
}
};
int main()
{
int sizeR, sizeC;
double val;
cout << "Enter No. Rows: ";
cin >> sizeR;
cout << "Enter No. Columns: ";
cin >> sizeC;
double * input_data;
input_data = new double[sizeR*sizeC];
//INPUTS VALUES TO ARRAY
for(int i = 0; i < sizeR*sizeC; i++)//Loops for every row
input_data[i] = i;
Matrix M1(sizeR, sizeC, input_data);
cout << "Enter row that value you are after is in: ";
cin >> sizeR;
cout << " & now the column that it is in: ";
cin >> sizeC;
cout << "Change value: " << M1.get(sizeR, sizeC) << " to:";
cin >> val;
M1.set(sizeR, sizeC, val);
//calls copy constructor
M1 = Matrix(M1);
}
In the copy-constructor you copy the pointer, meaning you you now have two objects both having the same pointer. If one of those objects are destructed, then it leaves the other object with a now invalid pointer.
Dereferencing this pointer in anyway, or attempting to free it, will lead to undefined behavior.
The problematic line in question is this one:
M1 = Matrix(M1);
That line creates a temporary object, and copies the data from M1 into that temporary object, then it assigns the temporary object back to M1 (and the compiler-generated copy-assignment operator will just do a shallow copy of the members, so not much different from your copy-constructor) and then destruct the temporary object, leading to the stray and invalid pointer in M1.
On a slightly related issue, you also might want to learn about the rule of three.
You are copying a pointer of one object into another inside the Copy constructor:
Matrix(const Matrix& oldMatrix)
{
...
data = oldMatrix.data;
After calling the copy constructor you have two objects referring to the same memoryblock. And if one object is destroyed the memory block is deleted and the second object points to an invalid memory location.
In the copy constructor you also need to allocate a new buffer!
A solution could be adding a bool variable (is_copy for instance) to your Matrix class. Set it to false on constructor and to true on copy constructor. Only deallocate memory in destructor if is_copy is false.
Or, as suggested in the comments, better use a smart pointer.

Program crashes on deleting array of pointers in struct

Crashes when the delete command comes around. It's supposed make a struct with pointers to arrays, fill them with random numbers, and then deallocate the memory. Works fine until the delete command, in which it crashes with our without the for loop or boolean check.
int main() {
cout << "start" << endl;
//Creating Struct
struct
{
int* ptrarray[10];
bool boolarray[10];
} data;
//Initializing Random Generator
srand ( time(NULL) );
cout << "Initializing: ";
//Allocating Memory and generating random numbers with for loops
for (int i = 0; i < 10; i++)
{
int counter = 0; //Counts numbers set
cout << i << " "; //Counting arrays initialized
data.ptrarray[i] = new int [12582912]; // Memory Allocation
for (int j = 0; j < 12582912; j++)//Number Generating
{
*data.ptrarray[i] = rand() % 899 + 100;
data.ptrarray[i]++;
counter++;
}
//Checking for failed initializations and declaring if success
if (counter == 12582912)
{
data.boolarray[i] = true;
}
else
{
data.boolarray[i] = false;
}
}
cout << endl;
//This is where it always crashes.
for (int i=0; i<10; i++)
{
if (data.boolarray[i] == true)
delete[] data.ptrarray[i];
}
cout << endl;
return 0;
}
I'm using MS Visual studio 2010.
The culprit is this line:
data.ptrarray[i]++;
You are changing the pointer, then using delete [] on the modified pointer. This will not work: you must use delete[] with the exact same pointer you got from new[].
Try
data.ptrarray[i][j] = rand() % 899 + 100;
instead so you don't have to change your pointer.
data.ptrarray[i]++; is the problem.
You're incrementing your reference to the data, but then not resetting it to the start before trying to delete it.
Your problem lies with:
data.ptrarray[i]++;
This is modifying the pointer. When you then attempt to free that modified pointer, it crashes.
You can solve this by using a copy of the pointer to run through the array, or by indexing with thej variable as well:
data.ptrarray[i][j]