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.
Related
I created a class that mimics the action of C++ vector by creating a dynamic array, I try to create a push back method for that class which first checks if the array is filled, if so it will:
1- Copy the contents of current array to a temporary array with the double size
2- Delete the old dynamic array
3- Create a new dynamic array with the double size of the old array (same size of temporary array)
4- Copy contents of the temporary array to the new dynamic array
the error is while I use the following code, I can only double the size of array once, then it throws to error:
HEAP[ConsoleApplication1.exe]: Invalid address specified to RtlValidateHeap( 016C0000, 016CDB98 )
ConsoleApplication1.exe has triggered a breakpoint.
#include <iostream>
using namespace std;
class SimpleVector {
private:
int* item; //pointer to the dynamic array (the vector)
int size;
int numElements;
public:
SimpleVector(int size) {
this->size = size;
this->numElements = 0;
this->item = new int[this->size];
}
SimpleVector():SimpleVector(10){}
void pushBack(int element) {
//check for overflow
if (numElements >= size) {
int newSize = size * 2;
int* temp = new int[newSize]; // temporary array with the double size to hold old array elements
for (int i = 0; i < numElements; i++) {
temp[i] = item[i];
}
delete[] item;
size = newSize;
//****ERROR IS IN THIS PART****
int* item = new int[size];
for (int i = 0; i < numElements; i++) {
item[i] = temp[i];
}
//****END OF THE PART CONTAINING ERROR****
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
else {
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
}
};
int main() {
SimpleVector v1(2);
v1.pushBack(1);
v1.pushBack(2);
v1.pushBack(3);
v1.pushBack(4);
v1.pushBack(5);
v1.pushBack(6);
v1.pushBack(7);
return 0;
}
This program pushs the first 4 items and then throws into error when trying to double the size form to 8
when I just replace that part containing error with:
item = temp
it works fine, but I can't understand why this happens.
Your code has several problems. I suggest you read about how to properly comply with Rule of Three/Five/Zero , which I'm not going to cover here. I only imagine this is for some nefarious academic purpose, so I will try to be brief, but please read the linked article.
That said, this:
int *item = new int[size];
for (int i = 0; i < numElements; i++)
{
item[i] = temp[i];
}
is pointless. This starts a cascade of bad actions that only gets worse as it rolls along.
You already have a member variable item. This code declares a local variable named item whose name hides the member item. Therefore the initialized value from the new operator is stored in the local, not the member.
That memory now pointed to by the local var item (not the member) is lost on exit of the function, since nothing but the local item ever points to it.
That additional allocation is pointless to begin with. You already made a new vector copy, pointed to by temp, and already copied all the legitimate items from memver-var item memory to temp memory. The code as-written leaks that temp allocation as well.
You destroy the member-var item memory, leaving the pointer now dangling, and any usage thereafter by dereference or eval invokes undefined behavior.
So, in summary, you make a valuable extended copy, leak it, make a worthless copy, leak it too, and end up leaving with a member variable that is no longer pointing at anything defined.
That entire function could look more like this:
void pushBack(int element)
{
// check for overflow
if (numElements >= size)
{
int newSize = size * 2;
int *temp = new int[newSize];
for (int i = 0; i < numElements; i++)
{
temp[i] = item[i];
}
delete[] item;
size = newSize;
item = temp;
}
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
For this assignment, I need to make a sorted copy of an array the user has given values to. All of my code works as intended, except for this specific part. I need this function (sortedCopy) to print out the sorted version of their array, without actually changing the array itself. As far as I can tell, to do so I need to used a constant version of the array in the function so the prototype would be something like: int *sortedCopy(const int *array, int size), but all this does is give the error shown in the title. Specifically:
main.cpp:72:29: error: assignment of read-only location '*(array +
((sizetype)(((long unsigned int)i) * 4)))' array[i] = array[min]
and it does this error twice, except with array[min] = temp; at the end instead
This is the code used, with the relevant parts of main:
#include <iostream>
using namespace std;
int* sortedCopy(const int *array, int size) {
int i, j, min, temp;
for (i = 0 ; i < size - 1; i++) {
min = i;
for (j = i + 1; j < size; j++) {
if (array[j] < array[min]) {
min = j;
}
}
temp = array[i];
array[i] = array[min];
array[min] = temp;
}
cout << "Sorted array is: " << endl;
for(int i = 0; i < size; i++) {
cout << array[i] << " ";
}
cout << endl;
// Not sure if I need to return anything or not either
}
int main() {
cout << "Please enter the size of the array." << endl;
int arraySize;
int array[arraySize];
cin >> arraySize;
cout << "Please enter integer values until the array is filled." << endl;
for (int i = 0; i != arraySize; i++) {
cout << "Value " << (i + 1) << ": ";
cin >> array[i];
cout << endl;
sortedCopy(array, arraySize);
for (int i = 0; i != arraySize; i++) { // I want this part to print the
cout << array[i] << " "; // original array entered by the user
}
}
If I remove the const part of the function, it works totally fine, except it will print the sorted array after the function is called, instead of the original array.
Firstly, C/C++ is best read "top-down":
int arraySize;
int array[arraySize]; // arraySize is undefined here!!
cin >> arraySize;
On the second line, ArraySize, might be 1, or 0, or -1000. You haven't defined it until line 3.
Also, C++ doesn't allow you to allocate arrays of variable size (unless that size is const [ so it is known at compilation time]):
int array[4];
The above is fine. This helps the operating system know how much memory to provide for you on the stack (it needs to do this before your programme starts running).
const int arraySize = 4;
int array[arraySize];
Because the C++ compiler knows that arraySize is 4, it processes this just like the above code, so this is also fine.
So to handle arrays of genuinely variable length (length that depends on inputs), you need to first read the user inputs, then use dynamic allocation ("new", or a container that does dynamic allocation for you, like a vector).
As for the problem with "const", what I think that you need to understand here is that "const" is really just a promise from the programmer: The programmer is communicating to the compiler (and any programmers reading the code) that this data is not supposed to change. All the compiler does is check whether you keep your promise (or if you send it to another function / pointer that doesn't hold that promise). So by using "const" there is no work done being done for you to actually keep the data constant - just that it will complain if you don't do the work.
int* sortedCopy(const int *array, int size) {
Above you're flagging to the compiler that the sortedCopy function will keep the data in the array constant.
array[i] = array[min];
array[min] = temp;
And here (above) you are breaking that promise.
If you don't want to edit the original array, then the easiest solution is just to copy it before you send it to your sorting function.
I am a getting a segment fault when trying to input data for my array of pointers. Im pretty new to coding so any help would be great. My task was to make an array of pointers then display, swap them around and than sort them
#include <iostream>
using namespace std;
float getValueFromPointer(float* thePointer)
{
return *thePointer;
}
float* getMinValue(float* a, float* b)
{
if (*a < *b)
{
return a;
}
else
{
return b;
}
}
int main()
{
int arraySize;
cout << "Enter the array size: ";
cin >> arraySize;
float** speed = new float*[arraySize]; // dynamically allocated array
for(int i = 0; i < arraySize; i++)
{
cout << "Enter a float value: ";
cin >> *speed[i];
}
// Core Requirement 2
for (int i = 0; i < arraySize; i++)
{
float value = getValueFromPointer(*speed+i);
cout << "The value of the element " << i << " is: ";
cout << value << endl;
}
//float *pointerToMin = getMinValue(&speed[0], &speed[arraySize - 1]);
//cout << *pointerToMin << endl;
delete [] speed;
speed = NULL;
return 0;
}
You’ve only allocated space for the outer array but you need to also allocate space for each of the internal floats.
So before calling this line:
cin >> *speed[i];
You need to first allocate space for it:
speed[i] = new float;
Your problem is that you've allocated an array of float pointers. You need to allocate an array of floats. So currently you have no memory allocated for the actual floats. If you do this, you'll allocate that memory:
float *speed = new float[arraySize];
You don't have any need for a 2D/jagged array that I can see. If you start with the code above, the compiler errors should lead you right in the direction. (Basically you will start removing * from a lot of places in your code.)
EDIT
Based on your requirement that I misunderstood, a possible approach is the following. The other answer (the one that isn't mine) makes sense in broader scenarios than this, but hopefully this is sort of another angle to think about that rather arbitrary problem you're trying to solve:
int main()
{
float *pFloats = new float[10];
float **ppFloats = new float*[10];
//assign float values and pointers to them in same loop
for (int i = 0; i < 10; i++)
{
pFloats[i] = i;
ppFloats[i] = &pFloats[i];
}
//swap two arbitrary pointers
float *pTemp = ppFloats[4];
ppFloats[4] = ppFloats[5];
ppFloats[5] = pTemp;
//print our float array
for (int i = 0; i < 10; i++)
printf("%f\n", pFloats[i]);
//print our float array *through* our pointers
for (int i = 0; i < 10; i++)
printf("%f\n", *ppFloats[i]);
delete[] ppFloats;
delete[] pFloats;
}
Ignore the hard-coded constants, etc...The point here is that I've created a contiguous memory area for the floats, and then created an array of float pointers on top of it. Note that I can sort my pointer array with zero impact on the original array. There are much smarter ways to do this, but...looks like you're learning about raw pointers, so...
Contrast with the other answer which creates jagged memory for the floats (1 at a time, on demand, not necessarily contiguous).
I've started picking up C++. The concepts are hard since I don't have any prior object-oriented programming experience. I am learning built-in arrays and constructors/destructors, and I have encountered an error that I cannot wrap my head around. Here, I'll show you guys the code.
The class definition goes
class arraysClass{
public:
int size1;
int size2;
int **frequencies;
arraysClass(int size1, int size2){
cout << "Constructor: size1&size2 " << size1 << " " << size2 << endl;
frequencies = new int*[size1+1];
for (int i=0; i<=size1; i++){
frequencies[i] = new int[size2+1];
}
}
//Destructor
~arraysClass()
{
cout << "Destructor: size1&size2 " << size1 << " " << size2 << endl;
for (int i=0; i<=size1; i++){
delete [] frequencies[i];
}
delete [] frequencies;
}
};
and here is my main function
int main()
{
int size1 = 20;
int size2 = 30;
arraysClass arrays1(size1, size2);
arraysClass arrays2 = arrays1;
arrays2.size1 = size1;
arrays2.size2 = size2;
return 1;
}
What I get as the result is
Constructor: size1&size2 20 30
Destructor: size1&size2 20 30
Destructor: size1&size2 0 0
a.out(41138,0x7fff75694000) malloc: *** error for object 0x7fa2eac032d0: pointer being freed was not allocated
The weird thing is that the constructor was only called once, when there is clearly a second instance of my class object. I have not made any copy constructors or overloaded the operator= function, so I'm not really sure what to make of this situation.
Anyone care to help a hopeless college student? Thanks!
arraysClass arrays2 = arrays1; Here default copy constructor was invoked and member int **frequencies was copied to arrays2. The catch is - this is so called, shallow copy, i.e. only pointer value is copied and both pointers pointing to same memory.
At the end of main function, both arrays1 and arrays2 are destroyed, and in destructor, int **frequencies (remember, they are pointing to same location) deleted twice. And so, first delete is going fine, second one is crashing program, because deleting already deleted pointer is undefined behavior.
Correct fix here is to make deep copy in copy constructor and overloaded operator=.
Example with copy constructor:
arraysClass(const arraysClass& rhs) {
cout << "Copy Constructor" << endl;
size1 = rhs.size1;
size2 = rhs.size2;
frequencies = new int*[size1+1];
for (int i=0; i<=size1; i++){
frequencies[i] = new int[size2 + 1];
memcpy(frequencies[i], rhs.frequencies[i], rhs.size2 + 1)
}
}
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