I have these scenarios and I want to know if I manage my memory correctly. I watch the memory consumption in the Task Manager when I start the executable and see how memory is not popped back to the initial amount, which leads me to suspect that I don't clear memory where is needed.
So, in this first case I have a function that adds a new element to a dynamic array:
struct Color {
int R;
int G;
int B;
}
int TotalColors;
Color* Rainbow;
void AddColor(Color NewColor) {
// So, I create a new array of size TotalColors+1
Color* NewRainbow = new Color[TotalColors+1];
// Now I add the existing elements
for (int i=0; i<TotalColors; i++) {
NewRainbow[i] = Rainbow[i];
}
// And lastly, I add the new element
NewRainbow[TotalColors] = NewColor;
// Now, I assign the NewRainbow to Rainbow (I don't know if it's correct)
Rainbow = NewRainbow;
}
So, in this case, do you think I miss something? This is working but I want to make sure the unused stuff is removed from memory.
I also have a function to remove an element, which looks like this:
void RemoveColor(Color Removable) {
// Again, I create a new array of size TotalColors-1
Color* NewRainbow = new Color[TotalColors-1];
// I scan the list and add only those elements which are not 'Removable'
for (int i=0; i<TotalColors; i++) {
// Let's suppose that Removable exists in the list
if (Rainbow[i].R != Removable.R && Raibow[i].G != Removable.G && ... {
NewRainbow [i] = Rainbow[i];
}
}
// Again, the same operation as above
NewRainbow[TotalColors] = NewColor;
Rainbow = NewRainbow;
}
In this case, I don't know what happens with Rainbow[Removable], I mean, the element of the array that is removed.
And the last case, is this, where I try to send the pointer of an element from the array to a function.
Color* GetColor(int Index) {
Color* FoundColor;
// Scan the array
for (int i=0; i<TotalColors; i++) {
if (i == Index) FoundColor = &Rainbow[i];
}
return FoundColor;
}
// And I use it like this
void ChangeColor(int Index) {
Color* Changeable;
Changeable = GetColor(Index);
SetRGB(Changeable, 100, 100, 100);
}
// And this is what changes the value
void SetRGB(Color* OldRGB, int R, int G, int B) {
(*oldRGB).R = R;
(*oldRGB).G = G;
(*oldRGB).B = B;
}
And this is it. So, this works but I am not sure if with so many pointers I didn't forget to delete something. For example, when I RemoveColor I don't see the memory changed (maybe some bytes don't make the difference) and I just want some professional eye to tell me if I missed something. Thanks!
In the first function AddColor() you are not deleting the previously allocated memory.
Rainbow = NewRainbow; // leaking the memory Rainbow was previously pointing to.
Change that last line to:
delete[] Rainbow;
Rainbow = NewRainbow;
Same thing with RemoveColor()
Any time you use the new operator it needs to have a corresponding delete. Also, if you are allocating an array with new[] as in your case, it must have a corresponding delete[].
In order not to worry whether you've forgotten to delete a pointer, you shouldn't use plain pointers. Instead, use smart pointers such as
std::shared_ptr
std::unique_ptr
etc.
or, if you don't have C++11 yet, use
boost::shared_ptr
boost::scoped_ptr
More on smart pointers, see Wikipedia and the specific documentation.
Related
I am new to c++(have a java background) and thus pointers are sort of new to me. I am dealing with an array of pointers where each index points to an object on the heap as so:
Deck::Deck()
{
seed = rand()%100; //this will be used in shuffle method
srand(seed);
for(int i=0;i<deckSize;i+=3) //deckSize=12 in this case, p defined as CardTypes* p[deckSize]
{
p[i]= new Infantry();
p[i+1] = new Artillery();
p[i+2] = new Cavalry();
}
}
All 3 of these classes are subclasses of the class CardTypes(which was only created so I could store diff types in an array).
class CardTypes
{
public:
virtual string getCard() = 0;
virtual ~CardTypes() {};
};
class Infantry: public CardTypes
{
const string name = "Infantry";
public:
string getCard(); //this simply returns "name" so that I can differentiate each object in the array by a data value
};
class Artillery:public CardTypes
{
const string name= "Artillery";
public:
string getCard();
};
class Cavalry:public CardTypes
{
const string name = "Cavalry";
public:
string getCard();
};
Although not a great way to do it, I have created another array of pointers(CardTypes* s[deckSize) which copies pointers from p into s randomly(thus mimicking a shuffle in a deck of cards):
void Deck::shuffle() //this is the method that puts objects in s to be grabbed in draw()
{
int j = 0;
int k = 1;
int l = 2; //initial setup(index 0 will have Infantry, index 1 will have Artillery and index 3 will have Cavalry and this pattern continues throughout p)
int n = rand()%3 + 1; //gives random # between 1 and 3 1=infantry,2 = artillery,3 = cavalry
int i=0; //counter for loop
while(i<deckSize)
{
n = rand()%3+1;
if(n==1)
{
if(j>9) //means no more infantry cards as due to pattern of p
infantry cards stop after index 9
{
continue; //used to reset loop foranother iteration(will get random number,I know this is bad for time complexity)
}
else
{
s[i] = p[j]; //copy "Infantry" pointer to s
j+=3;
i++;
}
}
else if(n==2)
{
if(k>10)//means no Artillery cards due to pattern in p
{
continue;
}
else
{
s[i] = p[k];//copy "Artillery" pointer to s
k+=3;
i++;
}
}
else
{
if(l>11) //means no more cavalary cards due to pattern in p
{
continue;
}
else
{
s[i] = p[l]; //copy "Cavalry" pointer to s
l+=3;
i++;
}
}
}
}
Now my issue is i am trying to create a draw method that grabs a pointer from s and returns it. My program completely crashes when I attempt this and I am not sure why:
CardTypes* Deck::draw() //draws a card from the deck and returns it
{
CardTypes* card = s[deckSize];
delete s[deckSize];//clear heap
s[deckSize] = NULL;//remove what pointer was pointing too (as card has been drawn)
deckSize--;
return card;
}
I then attempt to call this method:`
int main()
{
Deck d1;
d1.shuffle(); //this works
d1.getCurrentDeck();//this works, just prints out each objects getCard() method in s
CardTypes* card = d1.draw();//does not cause a crash
cout<<"Card:"<<card->getCard() <<"\n";//crashes here
}
This issue is probably due to my inexperience with pointers but any help would be appreciated. Also note I delete the arrays after I am done with the program using delete [] p and delete [] s, I have not included this in the code as it is not of issue right now.
You are struggling with pointer ownership. You understand that in C++ one must delete a pointer when it is no longer needed, but in Deck::draw you delete a pointer when it is still needed.
CardTypes* Deck::draw()
{
CardTypes* card = s[deckSize]; // s and card point to same allocation
delete s[deckSize]; // boom! card points to garbage.
s[deckSize] = NULL;
deckSize--;
return card;
}
You can use raw pointers, but you need to do it with a lot of coding maturity and deliberation.
Or you can say Smurf it and protect yourself from accidents like this with smart pointers. What is a smart pointer and when should I use one?
std::unique_ptr bundles ownership of a pointer. Only one std::unique_ptr is allowed at a time. You can't copy it. It as to be moved everywhere, transferring ownership from one holder to the next. But in the end there can be only one. You have to go out of your way to be stupid with a unique_ptr. Making five unique_ptrs and pointing them all at the same pointer, yeah you can do that. Put a self-destructing Automatic variable in a unique_ptr, yeah you can do that (and sometimes you do, but with a custom deleter that does nothing).
unique_ptr is the owner of the pointer. Whoever has the unique_ptr is owner by proxy because as soon as they get rid of the unique_ptr, the pointer goes with it.
Let's take a look at what we can do with a std::unique_ptr<CardTypes> to corral these wild pointers. If s is an array of unique_ptrs, std::unique_ptr<CardTypes> s[MAX_DECK_SIZE];, draw becomes
std::unique_ptr<CardTypes> Deck::draw()
{
std::unique_ptr<CardTypes> card = std::move(s[deckSize]);
// delete s[deckSize]; don't. Card now owns the card
// s[deckSize] = NULL; handled by moving ownership
deckSize--;
return card;
}
This can be simplified to
std::unique_ptr<CardTypes> Deck::draw()
{
return std::move(s[deckSize--]);
}
decksize-- is a post decrement so it happens after and the rest of the work is managed by the unique_ptr when it is moved out of s;
Sadly this means
s[i] = p[j];
ain't so easy anymore. You need
s[i] = std::move(p[j]);
But only if p no longer needs its jth element, because s[i] owns it now, baby.
Too little information has been provided in the question to wrangle this properly, but...
It's very possible that you could keep p full of unique_ptrs and load s with raw pointers whose lifespan is governed by p and pass s's pointers around naked and free without ever deleteing them because you know p has your back. So long as you keep p around longer than s and whoever s gives pointers to. It all comes back to ownership and in this case p owns all the Cards.
That turns
s[i] = std::move(p[j]);
into
s[i] = p[j].get();
and draw into
CardTypes * Deck::draw()
{
return s[deckSize--];
}
and makes life really, really easy.
Your problem is you are deleting the instance and, after that, you want to use it.
You are creating many instances:
for(int i=0;i<deckSize;i+=3) //deckSize=12 in this case, p defined as CardTypes* p[deckSize]
{
p[i]= new Infantry();
p[i+1] = new Artillery();
p[i+2] = new Cavalry();
}
The size of your array is determined by the variable deckSize.
In your function Deck::draw() your have some errors:
You are set a pointer of an instance of CardType with this code: CardTypes* card = s[deckSize]; But the array s has an index base 0, so s[deckSize]is accessing another memory sector that is not assigned to array s (Could a Memory Access Violation). use s[deckSize-1] instead of s[deckSize]..
You are release the memory that was assigned to pointer card and this pointer is returned to be used outside the function, which try to use this instance but is doesn't exist any more. So the memory which card and s[deckSize] share is released. Don't forget that s[deckSize] could raise a Memory Access Violation.
Check your code:
CardTypes* Deck::draw() //draws a card from the deck and returns it
{
CardTypes* card = s[deckSize-1]; //Assign the pointer to card.
delete s[deckSize-1];//DELETE THE INSTANCE (The memory that
return card; //The card points to a memory previously released.
}
Here is the moment that you are trying to use an unallocated:
CardTypes* card = d1.draw();//Get the pointer to s[deckSize-1]
cout<<"Card:"<<card->getCard() <<"\n";//crashes here
UPDATE:
Answer your comment, You can do this:
1.- Get the referencer to instance: CardTypes* card = s[deckSize-1];.
2.- Set the slot of your array in NULL and decrease the index:
s[deckSize-1]=NULL;
deckSize--;.
3.- Return de reference saved in card to upper level: return card;.
4.- Use the reference returned as you need it:
CardTypes* card = d1.draw();
cout<<"Card:"<<card->getCard() <<"\n";.
5.- Finally, delete de instance once you have finished to use it, for example just after the invocation of getCard():
cout<<"Card:"<<card->getCard() <<"\n";
delete card;
It's important to say that you decide where and when reserve, use and release the memory; just keep in mind to do it in an organized way and apply best practices, like these:
https://www.codeproject.com/Articles/13853/Secure-Coding-Best-Practices-for-Memory-Allocation
http://www.embeddedstar.com/technicalpapers/pdf/Memory-Management.pdf
I have a structure which includes a string field. I create an array of those structures and then I want to pass them to a function (by reference). Everything works perfectly fine when I comment out the string field, but if I don't the program crashes. I can't find an answer to this anywhere..
Here's the code (I reduced it to only show the issue):
struct student {
int a;
int b;
string name[20];
char status;
};
void operation(student the_arr[1],int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
for(int i = 0; i<3; i++) {
the_arr[i].a = i+5;
the_arr[i].b = i+4;
}
}
int main() {
student *abc;
abc = new student[0];
operation(abc, 0);
system("pause");
return 0;
}
I need the array to be dynamic so I can change its' size when I need to.
Assuming you can't use std::vector instead of dynamically allocated arrays follow the answer below. In any other case you should use the containers provided by the standard library.
Note: Your program doesn't crash. The only things the compiler will complain about it the allocating zero elements part, but will let you compile and run this program.
Your function is completely wrong. When using dynamic allocation you can simply pass a pointer like this:
void operation(student* the_arr, int number_of_students) {
Then inside your function you are dynamically allocating memory which is stored inside the the_arr pointer which is not passed by reference therefore leading to the creation of a local pointer variable that will lose the pointer after its execution:
void operation(student*& the_arr [...]
I suggest you to avoid the below solution though and return the new pointer instead:
student* operation(student* the_arr, int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
[...]
return the_arr; // <----
}
Allocating abc = new student[0]; doesn't make any sense. You are trying to allocate an array of 0 elements. Maybe you meant abc = new student[1];?
You should just use the vector or other sequence objects. Though I'm not sure what you are trying to do with your code. Here's a quick example:
// Vector represent a sequence which can change in size
vector<Student*> students;
// Create your student, I just filled in a bunch of crap for the
// sake of creating an example
Student * newStudent = new Student;
newStudent->a = 1;
newStudent->b = 2;
newStudent->name = "Guy McWhoever";
newStudent->status = 'A';
// and I pushed the student onto the vector
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );
If I declare an array on the heap, how can I get information about the array?
Here is my code:
class Wheel
{
public:
Wheel() : pressure(32)
{
ptrSize = new int(30);
}
Wheel(int s, int p) : pressure(p)
{
ptrSize = new int(s);
}
~Wheel()
{
delete ptrSize;
}
void pump(int amount)
{
pressure += amount;
}
int getSize()
{
return *ptrSize;
}
int getPressure()
{
return pressure;
}
private:
int *ptrSize;
int pressure;
};
If I have the following:
Wheel *carWheels[4];
*carWheels = new Wheel[4];
cout << carWheels[0].getPressure();
How can I get call the .getPressure() method on any instance in the array when it is on the heap?
Also, if I want to create an array of Wheel on the heap, yet use this constructor when creating the array on the heap:
Wheel(int s, int p)
How do I do this?
Wheel *carWheels[4];
is an array of pointers to Wheel, so you need to initialize it with new:
for ( int i = 0; i < sizeof(carWheels)/sizeof(carWheels[0]); ++i)
carWheels[i]=new Wheel(); // or any other c-tor like Wheel(int s, int p)
later you can access it like that:
carWheels[0]->getPressure();
size of array can be retrieved like above:
sizeof(carWheels)/sizeof(carWheels[0])
[edit - some more details]
If you want to stick to array you will need to pass its size on function call because arrays decays to pointers then. You might want to stay with following syntax:
void func (Wheel* (arr&)[4]){}
which I hope is correct, because I never use it, but better switch to std::vector.
Also with bare pointers in arrays you must remember to delete them at some point, also arrays does not protect you against exceptions - if any will happen you will stay with memory leaks.
Simple, replace
Wheel *carWheels[4];
with
std::vector<Wheel*> carWheels(4);
for ( int i = 0 ; i < 4 ; i++ )
carWheels[i] = new Wheel(4);
You seem to be confusing () and [], I suggest you look into that.
You do know that ptrSize = new int(30); doesn't create an array, right?
Like C, you will need to lug the array's element count around with your allocation.
This information is actually stored by the implementation in some cases, but not in a way which is accessible to you.
In C++, we favor types such as std::vector and std::array.
Other notes:
ptrSize = new int(30); << creates one int with a value of 30
How do I do this?
Wheel(int s, int p)
Typically, you would just use assignment if you have an existing element:
wheelsArray[0] = Wheel(1, 2);
because you will face difficulty creating an array with a non-default constructor.
and while we're at it:
std::vector<Wheel> wheels(4, Wheel(1, 2));
is all that is needed to create 4 Wheels if you use vector -- no new required. no delete required. plus, vector knows its size.
In C++, I'm having trouble with pointers etc. How can I fix the following problem?
error: no match for 'operator=' in '(stage->Stage::tiles + ((unsigned int)(((unsigned int)t) * 12u))) = (operator new(12u), (, ((Tile*))))'|
note: candidates are: Tile& Tile::operator=(const Tile&)|*
stage.h
#include "Tile.h"
class Stage {
public:
Tile *tiles;
int size;
void init(int size);
};
stage.cpp
void Stage::init(int size) {
this->size = size;
this->tiles = new Tile[size];
}
application.cpp
#include "Stage.h"
#include "Tile.h"
bool setTiles( Stage * stage ) {
for( int t = 0; t < stage->size; t++ ) {
stage->tiles[t] = new Tile();
}
return true;
}
stage.init(1234);
setTiles( &stage );
Also, I don't really know when to use object.attribute and when to use object->attribute?
stage->tiles[t] = new Tile();
You're calling new on something that's not a pointer. True, tiles is a pointer to an array, however, each element of that array is NOT a pointer. In order for that work, you would need an array of pointers, or a pointer to a pointer ,such as:
Tile **tiles;
What you could also do is create a separate pointer object, allocate it, and then copy the data to your array element by using
stage->tiles[i] = *somePointer;
and then deleting the pointer afterwards to free that allocated memory. This will preserve the copy because you invoked the copy constructor.
You are trying to allocate a pointer with a pointer to an array. Try this one:
class Stage {
public:
Tile **tiles;
void init(int size);
};
stage->tiles[t] = new Tile();
The above is not a valid C++ code, which you are perhaps confusing with the way new is used in other language such as C#. Though new can be used to allocate dynamic memories, but assigning an object to a particular element in the dynamically created array doesn't need the new construct. In fact, the object is already created as soon as you called new Tile[size]. What you may want to do is, create an object of type Tile and assign it to a particular element in tiles.
Tile myTile;
// do something with myTile
this->tiles[0] = myTile;
new Tiles() returns a pointer to a Tiles instance.
Tile *tiles defines an array out Tiles, not pointers.
Start with Tile **tiles instead.
so I'm currently trying to migrate my Java experience to C++ by implementing various Data Structures for the sake of having them implemented at least once.
Would you mind giving me some advise? The problem I am having is mainly concentrated around the pointers in push(int value) and especially pop(). As push seems to be working correctly I found myself struggling to get the correct value back when pop'ing things. What's the matter?
PS: I also think, that since I allocate my array space manually I'd need to delete it aswell. How do I do that?
#ifndef STACK_H
#define STACK_H
class Stack
{
private:
int *stackArray;
int elementsInArray;
int allocatedArraySize;
int alpha;
int beta;
public:
Stack();
void push(int aValue);
int pop();
bool isEmpty();
int size() const;
};
#endif
and the implementation:
#include <iostream>
#include "Stack.h"
Stack::Stack()
{
alpha = 4;
beta = 2;
elementsInArray = 0;
allocatedArraySize = 1;
stackArray = new int[1];
}
void Stack::push(int aValue)
{
if (elementsInArray == allocatedArraySize)
{
int temporaryArray[allocatedArraySize*beta];
for (int i = 0; i < elementsInArray; i++)
temporaryArray[i] = stackArray[i];
stackArray = temporaryArray;
allocatedArraySize *= beta;
}
elementsInArray++;
stackArray[elementsInArray] = aValue;
}
int Stack::pop()
{
int result = -INT_MAX;
if (elementsInArray == 0)
return result;
if (elementsInArray > 0)
{
result = stackArray[elementsInArray-1];
elementsInArray--;
if (elementsInArray <= allocatedArraySize/alpha)
{
int temporaryArray[allocatedArraySize/alpha];
for (int i = 0; i < elementsInArray; i++)
temporaryArray[i] = stackArray[i];
stackArray = temporaryArray;
allocatedArraySize /= beta;
}
}
return result;
}
bool Stack::isEmpty()
{
if (elementsInArray == 0)
return true;
return false;
}
int Stack::size() const
{
return allocatedArraySize;
}
For starters, you should be post incrementing the index on the array, so change:
elementsInArray++;
stackArray[elementsInArray] = aValue;
to:
stackArray[elementsInArray++] = aValue;
or:
stackArray[elementsInArray] = aValue;
elementsInArray++;
Second, when you create the new temp array you are doing it inside the if statement... therefore it is a local variable and placed on the system stack and lost after you exit the if statement. So change
int temporaryArray[allocatedArraySize*beta];
to:
int *temporaryArray = new int[allocatedArraySize*beta];
Third, add in the delete you were talking about by saving the original pointer from stackArray before copying the location of tempArray and then perform the delete after you've made the pointer copy.
Finally, you'll have to make similar changes to your pop function...
You are using an array on the stack (not your stack - the program execution stack). It's the one called temporaryArray in your push function. The address of that array will be invalid when you return from that function (because other functions will use the stack to hold other data).
what you want to do is allocate that array on the heap. This is memory that stays around for your program as long as you need it. To do this, you would allocate your temporaryArray like
int * temporaryArray(new int[allocatedArraySize*beta]);
Then, after copying the elements from your old array, you would delete it by using:
delete [] stackArray;
Do this before assigning the stackArray with the temporaryArray.
There may be other issues with your data structure, but you are doing the basic indexing correctly and incrementing / decrementing the current index appropriately (though I would suggest preferring to use the preincrement / decrement forms when not using the temporary as a good habit to get in - ie. ++elementsInArray / --elementsInArray).
well, i'm sure you already know that you have stack as a generic (c++ call it templates) in the STD library. Assuming you are doing this as a code kata, i would start writing it as a template, so it can't take object types others than integers.
Also, if you are going to write more of these low-level structures (as part of your kata), write a thin class where you delegate all allocation, reallocation and allocated size tracking, and use that instead of using arrays directly.