Passing Class with a Pointer Member - c++

I have a simple matrix class which has a 2d integer pointer field in it. When I call following function multiple times, it gives me a glibc error on Linux machine. When I have "otherM.value = '\0';" add this line to the end of function, problem resolves. Could somebody explain me why I have this dangling pointer issue, although class is passed by copy, not by reference? Pointer members are passed by reference?
void matrix::sub(matrix otherM)
{
if(dimX!=otherM.dimX || dimY!=otherM.dimY)
return;
int** rowPtr = value;
int** otherMrowPtr = otherM.value;
for(int i=0;i<dimX;i++){
for(int j=0;j<dimY;j++){
(**rowPtr) = (**rowPtr) - (**otherMrowPtr);
(*rowPtr)++;
(*otherMrowPtr)++;
}
(*rowPtr)-=dimY;
(*otherMrowPtr)-=dimY;
rowPtr++;
otherMrowPtr++;
}
rowPtr = '\0';
otherMrowPtr = '\0';
otherM.value = '\0';
}
matrix::matrix(int x, int y){
dimX = x;
dimY = y;
// allocate here
value = new int*[dimX];
int** rowPtr = value;
for(int i=0;i<dimX;i++){
*rowPtr = new int[dimY];
rowPtr++;
}
}
matrix::~matrix(){
if(value!=NULL){
int** rowPtr = value;
for(int i=0;i<dimX;i++){
delete[] (*rowPtr);
rowPtr++;
}
rowPtr-=dimX;
delete[] rowPtr;
rowPtr = '\0';
}
value = '\0';
}

Did you implement copy constructor, assignment operator and destructor for your class? If not then go and implement those since you're managing a resource.

Related

Issues with dynamic arrays, pointers and copy-constructors

I'm having a lot of issues with creating a dynamic array containing objects.
As I've understood it, because my array is handling objects, the class stored in the array must have a copy constructor or an assignment operator so that all will be copied properly.
I've successfully created this program with a normal array of defined size. Now I have a lot of problems creating the same program with a dynamic array.
Class 1 The objects to be stored:
class objToBeStored{
private:
string dataToBeStored;
int sizeOfArray;
string *storedArray;
public:
objToBeStored(); //empty constructor
objToBeStored& operator =(const objToBeStored& o); // assignment operator
~objToBeStored(); //destructor (no code inside);
bool getData(istream &stream);
//.....other methods to do stuff
};
objToBeStored::objToBeStored(){
//empty
}
objToBeStored& objToBeStored::operator=(const objToBeStored& o){
if(this != o){
dataToBeStored = o.dataToBeStored;
for (int i = 0; i < sizeOfArray; i++){
storedArray[i] = o.storedArray[i];
}
}
return *this;
}
void objToBeStored::getData(istream &stream){
stream >> dataToBeStored >> sizeOfArray;
storedArray = new string[sizeOfArray];
for(int i = 0; i < sizeOfArray; i++){
stream >> storedArray[i];
}
return !stream.eof();
}
//.....other methods to do stuff
Class 2 contains the dynamic array that stores the above objects. Everything is working,except how I declared my dynamic array and the functions handling it. Therefore I will write this code below:
class storageArrayClass{
private:
storageArrayClass *store;
storageArrayClass *storptr;
int numberOfstored;
public:
storageArrayClass(); //empty constructor
~storageArrayClass();
void addElm(objToBeStored & o);
//other functions to do stuff
};
storageArrayClass::storageArrayClass(){ //constructor
numberOfstored = 0;
}
storageArrayClass::~storageArrayClass(){
}
void storageArrayClass(istream &stream) {
objToBeStored o;
o.getData(stream);
if(numberOfstored == 0){ //check it this is the first element
store = new objToBeStored[1]; //create a new array with length 1
store[(numberOfstored] = o; //store object
}else{
objToBeStored tmpStore = new objToBeStored[(numberOfstored+1]; //create a temp. array with 1 more position
for(int i=0; i < numberOfstored; i++){
tmpStore[i] = store[i]; //copy original array to the temp. array
storptr = &tmpStore[i]; // increment a point
}
storptr++; //increment pointer to last position
*storptr = o; //store object in last position
delete[] store; //delete the original array
store = new objToBeStored[(numberOfstored+1]; //create a new original array
store = tmpStore;//copy temp. array
}
}
I manage to add 3 objects to my dynamic array before I get the following error:
Process returned -1073741819 (0xC0000005) execution time : 5.059 s
Please help. I've read countless threads here, but I cannot get it to work.

Creating multiple objects and passing parameters through constructor

I am trying to understand how to create multiple objects(20 in the current case) and pass parameter to the constructor as shown in the comments of the code. Unfortunately, I cannot pass parameters as well as have an array of objects at the same time.
I tried this as well to create the object convector con(100,200, construct(20)); but it didn't seem to give the desired result
#include <iostream>
class construct {
public:
int a, b;
// Default Constructor
construct(int x1,int x2)
{
a = x1;
b = x2;
}
int getX1(){
return a;
}
int getX2(){
return b;
}
};
int main(){
int p,q;
construct* con = new construct[20](100,200);
for (unsigned int i = 0; i < 20; i++) {
p=con[i]->getX1();
q=con[i]->getX2();
printf("%d %d \n",p,q);
}
delete con;
return 1;
}
Expected result would be 20 objects created.
Just use std::vector. Seriously, there's no reason not to.
std::vector<construct> con(20, {100, 200});
Yeah, for this you are likely to need placement new sadly (or use std::vector, and pass a newly constructed object as the second argument).
// call global new (effectively malloc, and will leave objects uninitialised)
construct* con = (construct*)::operator new (sizeof(construct) * 20);
// now call the ctor on each element using placement new
for(int i = 0; i < 20; ++i)
new (con + i) construct(100, 200);

How can I prevent these memory leaks?

I met huge problem with memory leaks and I don't know where to put that "delete" to get rid of them. Below is part of my code, and there is a full one: https://pastebin.com/Wtk83nuH.
string* startowa(int& rozmiar)
{
rozmiar = 5;
string* tablica = new string[rozmiar];
for (int i = 0; i < rozmiar; i++)
tablica[i] = "text";
return tablica;
}
string* plusx(string* tab, int& rozmiar)
{
string tekst = "something";
string* tablica_3 = new string[rozmiar];
tablica_3[rozmiar - 1] = tekst;
for (int i = 0; i<rozmiar - 1; i++)
tablica_3[i] = tab[i];
return tablica_3;
}
string* minusx(string* tab, int& rozmiar)
{
string* tablica_3 = new string[rozmiar];
for (int i = 0; i < rozmiar; i++)
tablica_3[i] = tab[i];
return tablica_3;
}
int main()
{
int wybor = 1, rozmiar = 1;
string *tablica = startowa(rozmiar);
while (wybor != 55) {
cin >> wybor;
if (wybor == 1) {
rozmiar++;
tablica = plusx(tablica, rozmiar);
}
if (wybor == 6) wybor = 55;
else {
rozmiar--;
tablica = minusx(tablica, rozmiar);
}
// there were other "ifs" but its just a part of the code
}
for (int i = 0; i < rozmiar; i++)
cout << tablica[i] << endl;
delete[] tablica;
cin >> wybor;
getchar();
return 0;
}
The memory leak is your least problem in that source code. In fact, you don't need heap allocations at all in your example.
Here are some fast improvements:
- use "std::string" instead of just string, I guess you are using "using namespace std"
- do not return a pointer to string, you can just declare a string and return it
- do not use a reference to an int as a function parameter if you are not returning it
- use const as much as you can
- replace "string *" with "const string&" if you are not returning it
- do not allocate string on heap (with new), instead declare it on stack
- use vectors
You can use this great site and Scott Meyers books for other C++ good practices.
To prevent memory leaks like that, avoid manual memory management. There are a lot of tools available to you.
For example, take your string array:
string* startowa(int& rozmiar) {
rozmiar = 5;
string* tablica = new string[rozmiar];
// ...
}
This should be replaced by std::vector. And since a vector keep track of it's size, you don't need to pass the size as reference:
std::vector<std::string> startowa() {
// ...
std::vector<std::string> tablica(5);
// ...
}
Then, your function that operates on the array should take the vector by reference to about copies, and return another vector. Since a vector already has a function that insert a new element, your plusx function becomes this:
void plusx(std::vector<std::string>& tab) {
std::string tekst = "something";
tab.emplace_back(std::move(tekst));
}
And your minusx function becomes that:
void minusx(std::vector<std::string>& tab) {
tab.pop_back();
}
By the way, with a vector, you can completely remove your startowa function by replacing the call in your main by this:
// Was `string *tablica = startowa(rozmiar);`
std::vector<std::string> tablica(5, "text");
Since std::vector manages it's memory itself, you don't need to delete it anywhere.
If you don't want to use vector, you can alway use std::unique_ptr<std::string[]>. The only difference in you code would be to send tablica.get() to your functions, and use std::make_unique<std::string[]>(rozmiar) instead of new std::string[rozmiar]
The correct answer is use std::vector. For example:
vector<string> startowa(int& rozmiar)
{
rozmiar = 5;
vector<string> tablica(rozmiar);
for (int i = 0; i < rozmiar; i++)
tablica[i] = "text";
return tablica;
}
Note the return by value. Don't fall into the trap of thinking you're saving processing time by returning by reference. That vector goes out of scope and is destroyed at the end of the function. With a returned reference the best you can hope for is the caller receiving a load of garbage and crashing before any damage can be done.
A decent compiler will eliminate the copying when you return the vector by value, and if the compiler decides that it cannot, std::move will take care of that.
vector also knows how big it is, eliminating the need for rozmiar.
Now... What went wrong? Let's look at the code
int main()
{
int wybor = 1, rozmiar = 1;
string * tablica = startowa(rozmiar);
startowa allocated an array of strings and stored a pointer to the array in tablica.
while (wybor != 55)
{
cin >> wybor;
if (wybor == 1)
{
rozmiar++;
tablica = plusx(tablica, rozmiar);
plusx allocated a new array of strings, a pointer to which has been returned and written over the pointer returned by startowa. startowa's array is now effectively lost, leaked, as it is next to impossible to find again to delete[].
We would need to delete[] tablica; before making the assignment. Clearly we can't do this before calling plusx as tablica is a parameter, so we need to store a temp.
string * temp = plusx(tablica, rozmiar);
delete[] tablica;
tablica = temp;
But what if something unexpected happens and an exception is thrown? The code never hits the delete[] and BOTH allocations are lost. vector handles all this for you.
And back to the code
}
if (wybor == 6)
wybor = 55;
else
{
rozmiar--;
tablica = minusx(tablica, rozmiar);
Same problem and solution as above.
}
// there were other "ifs" but its just a part of the code
}
for (int i = 0; i < rozmiar; i++)
cout << tablica[i] << endl;
delete[] tablica;
One of an in-determinant number of allocations is released here. The rest are lost.
cin >> wybor;
getchar();
return 0;
}

Memory leaks from 2d array on heap

I'm having an issue with a lot of memory leaks from a class I've created. The assignment is requires creating a word search puzzle on the heap. I've created my destructor, copy constructor and overload the assignment operator.
I think there must be something wrong with one of these functions, because the final check to ensure it is working is to create objects in a loop, to see if it fails and my function is crashing. I've tried different forms of the destructor and I've tried changing around the copy and assignment operator with no luck. Kind of at a loss, and the lack of warnings is really making it difficult to debug without a proper understanding of the heap.
Any help would be really appreciated!
Here are some functions that are working with the heap.
JumblePuzzle::~JumblePuzzle(){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete jumble;
}
JumblePuzzle::JumblePuzzle(string word, string diff){
int i = 0;
toHide = word;
difficulty = diff;
jumble = buildArray();
fillArray();
hideWord();
}
JumblePuzzle::JumblePuzzle(JumblePuzzle& temp){
size = temp.size;
rowPos = temp.rowPos;
colPos = temp.colPos;
direction = temp.direction;
toHide = temp.toHide;
difficulty = temp.difficulty;
jumble = temp.getJumble();
}
JumblePuzzle& JumblePuzzle::operator=(const JumblePuzzle& right){
if (this != &right){
for (int i = 0; i < size; ++i){
delete jumble[i];
}
delete[] jumble;
size = right.size;
rowPos = right.rowPos;
colPos = right.colPos;
direction = right.direction;
toHide = right.toHide;
difficulty = right.difficulty;
jumble = right.getJumble();
}
return *this;
}
charArrayPtr* JumblePuzzle::buildArray() const{
charArrayPtr* array = new char*[size];
for (int i = 0; i < size; ++i){
array[i] = new char[size];
}
return array;
}
Here's the line its failing on.
int loopLimit =20;
for (int i = 0; i < loopLimit; i++)
JumblePuzzle jp("HIDDENWORD", "hard");
Thanks for any possible help!
EDIT:
Here is my .h file as well.
#ifndef JUMBLE_H_
#define JUMBLE_H_
#include <time.h>
#include <cstdlib>
#include <string>
using namespace std;
typedef char* charArrayPtr;
class BadJumbleException {
public:
BadJumbleException(const string&);
string& what();
private:
string message;
};
class JumblePuzzle{
public:
JumblePuzzle(string, string); //simple constructor
JumblePuzzle(JumblePuzzle&); //copy constructor
~JumblePuzzle(); //deconstructor
charArrayPtr* getJumble() const;
JumblePuzzle& operator=(const JumblePuzzle&);
//accessors
int getSize();
int getRowPos();
int getColPos();
char getDirection();
private:
//attributes
int size;
int rowPos;
int colPos;
char direction;
charArrayPtr* jumble;
string toHide;
string difficulty;
void fillArray();
void hideWord();
char randomDirection();
int randomNum(int);
charArrayPtr* buildArray() const;
};
#endif
and my getJumble. It's used to get the actual word search created. Returned a copy rather than the pointer so it cant be modified.
charArrayPtr* JumblePuzzle::getJumble() const{
charArrayPtr* tempJumble = new char*[size];
for (int i = 0; i < size; ++i){
tempJumble[i] = new char[size];
}
for (int i = 0; i < size; i++){
for (int j = 0; j < size; j++){
tempJumble[i][j] = jumble[i][j];
}
}
return tempJumble;
}
There is one major thing wrong with your code, and that is you failed to initialize the "size" member in the JumblePuzzle(string, string) constructor.
There are other things you should do:
1) Create a separate function to destroy the 2d array within the JumblePuzzle class. You seem to be copying the same loops to do this in multiple places. No need for that if you just call a function to do this work.
2) Your assignment and copy constructor are not exception safe. If new[] throws an exception during the creation of the copy, then the original object has invalidated data. In other words, you've destroyed the data, and when you want to create another 2d array, when new[] says "oops", you've destroyed your original data and can't get it back.

Expand and add a new object to a array inside a function

I'm trying to expand and add a new object to a array inside a function and have that array be effected outside the function as well (the arrays pointer is sent as a parameter).
void addMedia(Media* medias[], int &nrOfMedias, string title, int publYear, string author, int nrOfPages)
{
Media** tempArray = new Media*[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = medias[i];
}
delete [] medias;
medias = tempArray;
delete [] tempArray;
medias[nrOfMedias] = new Book(title, publYear, author, nrOfPages);
nrOfMedias++;
}
This code works great inside the function but when I get outside it the array is still empty. As i understand this it's because the pointer is changed inside the function but how can i expand the array without having it change the pointer?
(I can not change the return data type or the parameters, assignment requirements.)
Do change medias = tempArray; to *medias = tempArray;, make it compile, polish your memory management (consider, what really should be freed, what not).
Don't view medias as an array of pointers, view it as a pointer to an array. Working example (slightly simplified):
class Media
{
public:
Media () { m_strTitle = "unknown";}
string m_strTitle;
};
class Book : public Media
{
public:
Book(string strTitle) { m_strTitle = strTitle; }
};
void addMedia(Media* medias[], int &nrOfMedias)
{
Media * tempArray = new Media[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = (*medias)[i];
}
delete [] *medias;
(*medias) = tempArray;
(*medias)[nrOfMedias] = Book("newTitle");
nrOfMedias++;
}
int main()
{
int numMedia = 10;
Media * myArray = new Media[numMedia];
addMedia(&myArray, numMedia);
for (int i = 0; i < numMedia; i++)
{
cout << i << ") " << myArray[i].m_strTitle << endl;
}
return 0;
}
You don't need delete [] tempArray; because tempArray actually points to the same memory block as medias does after medias = tempArray;
Your function will work well whithout that line but I assume that you know what you pass with Media* medias[]