I am trying to implement a stack using an array. This is what I have in my
header file.I plan to assign the value to maxsize in the constructor. However, i keep getting errors. How can i fix this?
class stack {
private:
const int maxsize;
int arrays[maxsize];
int top;
public:
stack();
void additem(int);
void print();
};
A good fix would be:
class stack
{
std::vector<int> arrays;
int top;
public:
stack(int maxsize) : arrays(maxsize), top(0) {}
};
This way, you do not have any possibility of memory management bugs; your class behaves properly when copied, moved, swapped, etc. and your code is very simple.
An alternative, with a minimal memory footprint would be:
class stack
{
std::unique_ptr<int[]> arrays;
int maxsize;
int top;
public:
stack(int maxsize) : arrays(new int[maxsize]), maxsize(maxsize), top(0) {}
};
This version is movable, but will give compile errors when copied (as opposed to some of the other suggestions to use raw pointer, which will compile successfully and then give memory corruption at runtime). To make this class copyable you'd need to write your own copy-constructor and copy-assignment operator.
C++ doesn't allow variable-length arrays. Instead of an array, you can use a pointer and dynamic allocation.
And to initialize a const member, you have to do it in the initializer list of the constructor.
class stack {
private:
const int maxsize;
int *arrays;
int top;
public:
stack(int max = 10) : maxsize(max) {
arrays = new int[max];
top = 0;
}
void additem(int);
void print();
};
See How to initialize a const field in constructor?
You'll also then need a destructor that does delete[] arrays;.
But rather than using a C-style array, you'd probably find it easier to use std::vector<int>. This doesn't require specifying a maximum length in the first place, it will expand as needed.
Of course, you could skip this whole exersize and use std::stack<int>.
If you want maxsize to always be 10, you could do something like this:
class stack {
private:
static const int maxsize = 10;
int arrays[maxsize];
...
Note that I've made maxsize static. It will be the same for all instances of stack and is defined at compile time. Thus you can use it as an array size.
If you want maxsize to be variable, then you'll need to use dynamic allocation:
class stack {
private:
const int maxsize;
int* arrays;
...
public:
stack(int maxsize) : maxsize(maxsize), arrays(0) {
arrays = new int[maxsize];
}
~stack() { delete[] arrays; }
...
Note here that you must delete the memory you dynamically allocate. The usual place to do that is the destructor. If you want to go this route, you could also just use a std::vector<int> and get rid of maxsize entirely. That frees you from having to do any manual memory management.
Related
I build two classes, cell, and HashTable, I want to declare an array of cells as a hashTable class member.
I want to do it with primitive vars like int,chars, like I declare array of cars as a hashTable class member.
I tried to declare an array of cells in some ways :
1.
class HashTable{
public:
int size;
int numOfKeys;
Cell* table = new Cell[10];
int cars[4];
//static void resize(HashTable &ht);
static void reinsert(Cell* new_table, int new_size, Node<Player*> *data);
HashTable() : size(10), numOfKeys(0) {
table = new Cell[10];
}
2. class HashTable{
public:
int size;
int numOfKeys;
Cell* table = new Cell[10];
int cars[4];
//static void resize(HashTable &ht);
static void reinsert(Cell* new_table, int new_size, Node<Player*> *data);
HashTable() : size(10), numOfKeys(0),table(new Cell[10]) {
}
I try to declare it in the constructor but it doesn't work.
How am I supposed to define this array?
Thanks !
I don't see any error , but I can see the array of cars but not the array of table
class Cell
{
public:
AVLTree<Player*>* AllPlayers;
int treeSize;
Cell() : treeSize(0) {
AllPlayers = new AVLTree<Player*>();
}
~Cell(){
delete AllPlayers;
};
Cell(const Cell &sec) = default;
Cell &operator=(const Cell &sec) = default;
void reinsert(Player* pl)
{
treeSize++;
AllPlayers->root = AllPlayers->insert(AllPlayers->root, pl,NULL);
}
int insert(Player* pl)
{
if (!(AllPlayers->findNode(AllPlayers->root,pl)))
{
AllPlayers->root = AllPlayers->insert(AllPlayers->root,pl,NULL);
treeSize++;
return 0;
}
return -1;
}
int remove(Player* pl)
{
AllPlayers->root = AllPlayers->remove(AllPlayers->root,pl);
treeSize--;
return treeSize;
}
};
class HashTable{
public:
int size;
int numOfKeys;
Cell* table;
int cars[4];
//static void resize(HashTable &ht);
static void reinsert(Cell* new_table, int new_size, Node<Player*> *data);
HashTable() : size(10), numOfKeys(0) {
table = new Cell[10];
}
~HashTable() { delete[] table; }
Fear not! You have an array of ten Cells pointed at by table.
table is a pointer. It holds an address, nothing more. A pointer knows only where an object is (note that the object may have been subsequently destroyed, a pointer has no way of knowing, or the pointer may not have been initialized). If the object referenced to by the pointer is an array, the pointer has no way to know how many items are in the array. The IDE cannot show that there are ten items in the array pointed at by table because all it knows is the pointer and the pointer does not know. If you want the IDE to display what is in those ten Cells, you need to set up what are commonly called "watch expressions" for each subobject in the array or play games with casting to tell the watch expression how to interpret the object at the pointer.
cars is an array. Arrays represent the whole whole array. They know their size, their dimensions and all of the data in the array. The IDE can show you all of the items in the cars array because cars knows all that there is to know.
If you know you will always and forever have 10 Cells, get rid of the pointer and define an array. If you don't know the size, you'll have to live with what the IDE can show you.
Side note: Some IDEs are smart enough to interpret a std::vector and can display the objects in the std::vector. Consider using std::vector instead of a dynamic array where possible. Intelligent handing in IDEs is but a small benefit of std::vector.
Side note: When I say object, I mean it in the C++ definition of object, not in the OOP sense of an instance of a class.
I have an Image class and initially I do not know the image dimensions, so I just initialize a data_ pointer to be an array of size 0. Later when I find the image information I reinitialize data_ to a new size. Will this create any problem in memory? and is there a cleaner way to do this?
Below is the class I have written:
class Image
{
private:
int numRows_, numCols_;
unsigned char* data_;
public:
Image() : numRows_(0), numCols_(0), data_(new unsigned char[0])
{}
void setData(int r, int c, unsigned char* data)
{
this->numRows_ = r;
this->numCols_ = c;
this->data_ = new unsigned char[r*c];
for (int i = 0; i < r*c; i++)
{
this->data_[i] = data[i];
}
}
int rows();
int cols();
unsigned char* data();
~Image();
};
Thanks in advance
This will in fact leak memory. The call to new allocates memory for the array, even if it is empty. As soon as you reassign data_, the previous array is leaked and can no longer be freed.
You can either make sure you delete[] any new[] you allocate, or just don't allocate an empty array and instead set data_ to nullptr until you have meaningful data to use.
An even better idea is don't allow the creation of an object in an invalid state, require the data in the constructor - see RAII:
In RAII, holding a resource is a class invariant, and is tied to
object lifetime: resource allocation (or acquisition) is done during
object creation (specifically initialization), by the constructor,
while resource deallocation (release) is done during object
destruction (specifically finalization), by the destructor.
If you do decide to keep setData, then as mentioned in comments, you also must make sure to delete[] existing data in setData before reassigning data_, in case the method is called more than once.
I think a cleaner way to do so will be using a vector:
std::vector<unsigned char> v; // vector with size 0
v.resize(r*c); // after size is known, just resize
Following my understanding of C++ convention, I have:
class BlockRepresentation : public FPRepresentation
{
private:
class Block
{
public:
int id;
int fpDimensions;
int* position; // pointers in question
int* blockDimensions; // pointers in question
~Block();
};
std::vector<Block> all_blocks;
public:
BlockRepresentation( int count, int dimensions, int volumn[] );
void AddBlock( int id, int position[], int dimensions[] );
std::string ToGPL();
};
where new blocks are created in AddBlock:
void BlockRepresentation::AddBlock( int id, int position[],
int dimensions[] )
{
Block newBlock;
newBlock.id = id;
newBlock.fpDimensions = fpDimensions;
newBlock.position = new int[fpDimensions]; // pointers in question
newBlock.blockDimensions = new int[fpDimensions]; // pointers in question
for (int i = 0; i < fpDimensions; ++i)
{
newBlock.position[i] = position[i];
newBlock.blockDimensions[i] = dimensions[i];
}
all_blocks.push_back( newBlock );
}
so I have the following destructor:
BlockRepresentation::Block::~Block()
{
delete[] position;
delete[] blockDimensions;
}
but then I get:
rep_tests(11039,0x7fff71390000) malloc: *** error for object 0x7fe4fad00240: pointer being freed was not allocated
Why should I not delete[] the 2 pointers here?
As was pointed out in the comments, you violated the rule of three, and the violation is very obvious:
{
Block newBlock;
// snip
all_blocks.push_back( newBlock );
}
When this function returns, the newBlock object goes out of scope, and its destructor will delete all the newed arrays.
But you push_back()ed this object. This constructs a copy of the object into the vector. Because your Block does not define a copy constructor, the default copy-constructor simply makes a copy of all the pointers to the newed arrays.
If you somehow manage to avoid dereferencing the no-longer valid pointers, or you survived that experience, you're not of the woods yet. That's because, when the vector gets destroyed, and its Blocks get destroyed, their destructors will, once again, attempt to delete the same newed arrays that were already deleted once before.
Instant crash.
There is nothing wrong with your Block destructor. It is doing its job, which is releasing the memory that is pointed to by your two int * member variables. The problem is that the destructor is being called on the same pointer value multiple times, which results in a double-free error.
The entity that causes this is the std::vector<Block>, since a std::vector will make copies of your Block object, and your Block object is not safely copyable.
Since the member variables of Block that are pointers are position and blockDimensions, the most painless way to alleviate this issue is to use std::vector<int> instead of int *, as demonstrated by this sample program.
However, if you really wanted to use int *, you would need to implement a user-defined copy constructor. In addition, a user-defined assignment operator would complement the copy constructor. This is what is called the Rule of Three.
#include <algorithm>
//...
class Block
{
public:
int id;
int fpDimensions;
int *position;
int *blockDimensions;
Block() : position(nullptr), blockDimensions(nullptr),
id(0), fpDimensions(0) {}
~Block()
{
delete [] position;
delete [] blockDimensions;
}
Block(const Block& rhs) : id(rhs.id), fpDimensions(rhs.fpDimensions),
position(new int[rhs.fpDimensions]),
blockDimensions(new int[rhs.fpDimensions])
{
std::copy(rhs.position, rhs.position + fpDimensions, position);
std::copy(rhs.blockDimensions, rhs.blockDimensions + fpDimensions,
blockDimensions);
}
Block& operator=(const Block& rhs)
{
Block temp(rhs);
std::swap(temp.position, position);
std::swap(temp.blockDimensions, blockDimensions);
std::swap(temp.id, id);
std::swap(temp.fpDimensions, fpDimensions);
return *this;
}
};
See the live sample here.
See all of the hoops we had to jump through to get the Block class to behave correctly when used within a std::vector, as opposed to simply using std::vector<int>?
I have a question, i want to use my Heap array like "Heap[i].value=x" i have value and Heap array in private and i have in my constructor ,but when i want to use like "Heap[i].value" it says Intellisense "No members available". What should i do, i really stuck. Thanks.
In my header
class MPQ
{
private:
//const int ITEM_NOT_FOUND =-1;
int value;
int label;
int size;
int Currentsize;
int *Heap; //heap array
int*Location;
In my cpp my constructor is
MPQ::MPQ(int n)
{
value=0;
label=0;
size=n;
Heap=new int [n];
Location =new int [n];
for (int i=0;i<size;i++)
{
Heap[i]=-1;//ITEM_NOT_FOUND;
Location[i]=0;
}
Currentsize=0;
}
i want to use my Heap array like "Heap[i].value=x"
In that case, Heap cannot be an array of int because int does not have a member value. In fact, int does not have any members at all. To be able to use Heap like that, it must be an array of such objects that do have a member value.
I am trying to implement a stack using an array but I receive an error.
class Stack{
private:
int cap;
int elements[this->cap]; // <--- Errors here
int top;
public:
Stack(){
this->cap=5;
this->top=-1;
};
The indicated line has these errors:
Multiple markers at this line
- invalid use of 'this' at top level
- array bound is not an integer constant before ']' token
What am I doing wrong?
In C++, the size of an array must be a constant known at compile-time. You'll get an error if that isn't the case.
Here, you have
int elements[this->cap];
Notice that this->cap isn't a constant known at compile-time, since it depends on how big cap is.
If you want to have a variably-sized array whose size is determined later on, consider using std::vector, which can be resized at runtime.
Hope this helps!
You cannot use this in the declaration like that.
this is a constant pointer passed to non-static methods in your class. It does not exist outside of that scope.
Such array declarations need constant values/expressions for the size. You don't want that, you want a dynamicly sized container. The solution is to use a std::vector.
Since other have already explained the cause of this issue, here is a possible solution to resolve it. Since it seems you may not know the array size at compile time and the assignment may restrict the use of std::vector<int> consider using a pointer implementation.
#include <algorithm>
class Stack{
private:
int cap;
int* elements; // use a pointer
int top;
public:
Stack(){
this->cap=5;
this->top=-1;
elements = new int[this->cap];
}
Stack(const Stack& s)
: cap(s.cap) , top(s.top), elements(NULL)
{
if(cap > 0) {
elements = new int[cap];
}
std::copy(s.elements , s.elements + cap, elements );
}
Stack& operator=(Stack s) {
swap(s, *this);
return *this;
}
~Stack() {delete [] elements;}
friend void swap(Stack& first, Stack& second)
{
using std::swap;
swap(first.top, second.top);
swap(first.cap, second.cap);
swap(first.elements, second.elements);
}
};