C++ dynamically increase array size for object-array? - c++

I'm making a game with cocos2d-x. The different objects in the game i want to store in a class (I dont know if this is a good idea, but so i can give every object a lot of attributes). Then i make an array out of the objects and for that i need an own datastructure, where i can push and pop my objects. I tried to write this datastructure, but i think i doing wrong with my push function (i want to dynamically increase array size), especially the delete []? Doesn't that destroy my object-pointers stored?
ObjectArray.h:
#pragma once
#include "C:\Cocos\Projects\FirstGame\proj.win32\anObject.h"
class ObjectArrayList
{
public:
ObjectArrayList(int c);
ObjectArrayList();
virtual ~ObjectArrayList(void);
void push(anObject *obj);
void pop(int id);
int findIndex(int id);
int getSize();
int getCapacity();
private:
int capacity;
int size;
anObject **objectList;
};
ObjectArray.cpp:
#include "ObjectArrayList.h"
#include <iostream>
using namespace std;
objectArrayList::ObjectArrayList(int c)
{
size=0;
capacity = c;
objectList = new anObject*[capacity];
}
ObjectArrayList::ObjectArrayList() {
}
ObjectArrayList::~ObjectArrayList(void) {
}
void ObjectArrayList::push(anObject *obj) {
if(size < capacity) {
} else {
int newCap = 2*capacity;
anObject **tmpObjectList = new anObject*[newCap];
for(int i = 0;i<capacity;i++) {
tmpObjectList[i] = objectList[i];
}
delete [] objectList;
objectList = tmpObjectList;
capacity = newCap;
}
objectList[size] = obj;
size++;
}
void ObjectArrayList::pop(int id) { //not finish yet
if(size != 0) {
size--;
}
}
int ObjectArrayList::findIndex(int id) {
return id;
}
int ObjectArrayList::getSize() {
return size;
}
int ObjectArrayList::getCapacity() {
return capacity;
}
anObject.h:
#pragma once
#include "cocos2d.h"
class anObject
{
public:
anObject(int hp_init, int x, int y);
anObject();
virtual ~anObject(void);
void decreaseHp();
int getHp();
void setMyPosition(int x, int y);
cocos2d::Sprite *getMySprite();
private:
cocos2d::Sprite *mySprite;
int hp;
int midX;
int midY;
int isX;
int isY;
};
Bert

As the comments pointed out... you should save some time and energy and try to use the Standard Template Library (STL).
If you insist on fixing this code, I think you should try referencing objectlist after the delete to see if it's still there... maybe this assignment...
objectList = tmpObjectList;
...is not tolerated.
Instead... try to build a copy constructor "public Object(Object copiedObject){}", make a new Object*[] of the 2X size, populate it, then get rid of the old and... without deleting objectList assign your new Object*[] to it...
The rest seems fine to me... hope this helps.

delete [] objectList;
This only frees the array which objectList points to. It does not free any of the objects in that array.

Related

C API: Error allocating / deallocating memory for array

I'm in the process of implementing an API for C. The code base itself is purely written in C++ and I only plan to offer said interface for any consumer using C. The interface is defined in a .h file, whereas the implementation itself is written in C++. I've read multiple times that using C++ to implement a C interface is not the best idea, but it works great in my case.
Anyway the header definition looks similar to this:
extern 'C' {
typedef struct Person {
const char *name;
uint32_t age;
uint32_t post_code;
} Person;
typedef struct PersonArray {
Person *person;
size_t size;
} PersonArray;
PersonArray *create(size_t size);
void destroy(PersonArray *array);
int fillArray(PersonArray *array);
}
I'd like the consumer to retrieve a handle for PersonArray, which contains an array of Person structure, allocated with the size passed to the create() function.
Since the implementation is in C++ I've tried to allocate the memory the following way:
static inline Person convert(const otherNamespace::Person &o_person) {
Person p{};
p.name = o_person.name;
p.age = o_person.age;
p.post_code = o_person.post_code;
return p;
}
PersonArray *create(size_t size) {
if (size <= 0) {
return nullptr;
}
PersonArray *array = new PersonArray();
array->size = size;
array->person = new Person[size]
return array;
}
void destory(PersonArray *array) {
delete array;
}
int fillArray(PersonArray *array) {
if (array == nullptr) {
return 1;
}
auto data = // retrieve std::vector<otherNamespace::Person> via RPC
for (auto i{0U}; i < array->size; i++) {
array->person[i] = convert(data.at(i);
}
return 0;
}
Unfortunately, this approach does not seem to work correctly, because when using a memchecker like valgrind, there are still blocks on the heap that are not correctly deallocated. I suppose the line new Person[size] does not get deallocated.
Any idea how to fix this memory leak? Or is there another design which would be better suited for this specific use case? If possible, I would really like to keep the implementation in C++.
You must use delete on person before array, but since it was allocated with new [] you must delete it with delete [].
void destroy(PersonArray *array) {
if (array) {
if (array->person) {
delete [] array->person;
}
delete array;
}
}

error: "EXC_BAD_ACCESS(code=EXC_I386_GPFLT)" when i try to insert class objects in array of class objects c++

So i have created a class that creates an array of objects from another class and when i try to execute the program and insert new objects to the array i get this error: EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
Specifically on the insertion of the 10th element.
this is the class that has the array:
class Savelist{
private:
list_reserve *reserve;
list_user *users;
int length,MaxSize;
string code;
public:
string stoixeia;
Savelist(int MaxListSize)
{// Constructor for formula-based linear list.
MaxSize = MaxListSize;
reserve = new list_reserve (MaxSize, code);
users=new list_user(MaxSize);
length = 0;
}
~Savelist() {delete [] reserve,delete [] users;} // destructor
bool IsEmpty() const {return length == 0;}
int Length() const {return length;}
the method that inserts class objects to array:
void Insert_flight(list_reserve input)
{// "push" all objects one position up
if (length!=0)
{
for (int i=length-1; i >=0; i--)
{
reserve[i]=reserve[i+1];
}
reserve[0] = input;
length++;
}
else
{
reserve[0] = input;
length++;
}
}
here is the class that creates the objects that are being inserted to array:
class list_reserve {
private:
bool result;
int length,MaxSize;
string *object; // dynamic 1D array
public:
string code;
bool get_result;
// constructor
list_reserve(int MaxListSize,string flcode)
{// Constructor for formula-based linear list.
MaxSize = MaxListSize;
object = new string [MaxSize];
length = 0;
code=flcode;
}
~list_reserve() {delete [] object;} // destructor
bool IsEmpty() const {return length == 0;}
int Length() const {return length;}
the method that inserts simple strings to the object of that class:
void Insert_User(string input,string code,list_flight schedule)
{// Insert user
if (length!=0)
{
for (int i=length-1; i >=0; i--)
{
object[i+1] = object[i];
}
object[0] = input;
schedule.Get(code);
schedule.update(schedule.code, 1);
length++;
}
else
{
object[0] = input;
schedule.Get(code);
schedule.update(schedule.code, 1);
length++;
}
}
};
And lastly the main():
int main(int argc, const char * argv[]) {
list_reserve DA001_r(100,"DA001"),DA002_r(100,"DA002"),DA003_r(100,"DA003"),DA004_r(100,"DA004"),DA005_r(100,"DA005")
,DA006_r(100,"DA006"),DA007_r(100,"DA007"),DA008_r(100,"DA008"),DA009_r(100,"DA009"),DA010_r(100,"DA010"),DA011_r(100,"DA011")
,DA012_r(400,"DA012"),DA013_r(400,"DA013"),DA014_r(100,"DA014"),DA015_r(100,"DA015"),DA016_r(100,"DA016"),DA017_r(100,"DA017")
,DA018_r(100,"DA018"),DA019_r(100,"DA029"),DA020_r(100,"DA020"),DA021_r(100,"DA021"),DA022_r(100,"DA022"),DA023_r(400,"DA023"),
DA024_r(400,"DA024");
Savelist Queues(100);
Queues.Insert_flight(DA001_r);
Queues.Insert_flight(DA002_r);
Queues.Insert_flight(DA003_r);
Queues.Insert_flight(DA004_r);
Queues.Insert_flight(DA005_r);
Queues.Insert_flight(DA006_r);
Queues.Insert_flight(DA007_r);
Queues.Insert_flight(DA008_r);
Queues.Insert_flight(DA009_r);
Queues.Insert_flight(DA010_r);
Queues.Insert_flight(DA011_r);
Queues.Insert_flight(DA012_r);
Queues.Insert_flight(DA013_r);
Queues.Insert_flight(DA014_r);
Queues.Insert_flight(DA015_r);
Queues.Insert_flight(DA016_r);
Queues.Insert_flight(DA017_r);
Queues.Insert_flight(DA018_r);
Queues.Insert_flight(DA019_r);
Queues.Insert_flight(DA020_r);
Queues.Insert_flight(DA021_r);
Queues.Insert_flight(DA022_r);
Queues.Insert_flight(DA023_r);
Queues.Insert_flight(DA024_r);
}
You really, really don't want to store owning pointers to dynamically allocated resources in classes. For a good rundown on why see this answer on what's necessary to store an owning pointer in a class. Using a standard container such as std::vector also greatly simplifies the code as these implement most common operations you may want to do with them, such as insertion, deletion and the like.
For instance, your Savelist class would become the following when using std::vector
class Savelist {
private:
vector<list_reserve> reserve;
vector<list_user> users;
// No need for storing MaxSize or length, std::vector can store any
// number of elements, and knows how many elements it contains.
string code;
public:
string stoixeia;
// constructor and destructor becomes unnecessary, as the vector member
// takes care of all the bookkeeping
bool IsEmpty() const { return reserve.empty(); }
int Length() const { return reserve.size(); }
// Insert flight need only pass the input to the vector
void Insert_flight(list_reserve input) { reserve.insert(reserve.begin(), input); }
};
And similarly for the list_reserve class
class list_reserve {
private:
bool result;
// once again, the vector keeps track of size and elements contained
vector<string> object;
public:
string code;
bool get_result;
// constructor becomes simpler
list_reserve(string flcode)
{
code = flcode;
}
// destructor becomes unnecessary
bool IsEmpty() const { return object.empty(); }
int Length() const { return object.size(); }
void Insert_User(string input, string code, list_flight schedule)
{
// note that object.push_back(input); would be
// more efficient, but inserts the element at the end.
object.insert(object.begin(), input);
schedule.Get(code);
schedule.update(schedule.code, 1);
}
};
See also cppreference page on std::vector for an excellent reference on what's available.

C++: how to get element defined in a different function of same class?

I defined a class in the header file like this:
class myClass
{
public:
void test();
void train();
private:
bool check;
}
Then in the cpp file, I did this:
void myClass::test()
{
int count = 9;
//some other work
}
void myClass::train()
{
int newValue = count;
....
}
Then without surprise, I got an error saying count is not defined. So what I want to do is in my train function use the count value that is defined in the test. Is there any good way to do this without using any additional dependencies? Thank you.
Well yes. That's called a member variable. Exactly like your bool check;.
Do
private:
bool check;
int count;
and then use it directly in your functions.
void myClass::test()
{
count = 9;
//Same as this->count = 9;
}
void myClass::train()
{
int newValue = count;
//Same as int newValue = this->count;
}
In your example, when method test finishes its work, count variable does not exist anymore, so there's no way of accessing it. You have to ensure, that its lifetime will be long enough to be accessed from another place. Making it a class field solves the problem (this is what class fields are for :)).
Do it this way:
class myClass
{
public:
void test();
void train();
private:
bool check;
int count; // <- here
}
and then
void myClass::test()
{
count = 9;
//some other work
}
But that's not the only solution. You can do it in another way, say:
class myClass
{
public:
int test()
{
// do some work
return 9;
}
void train(int count)
{
int newValue = count;
}
}
// (somewhere)
myClass c;
int count = c.test();
c.train(count);
That all depends on what test, train and count are for...

Pointer to object with vector memory leak

I seem to have a little memory leak problem with vectors.
My code looks like this:
class CPart {
public:
virtual void print() = 0;
};
//some other classes
class CDisk : public CPart {
public:
CDisk(int tp, int size);
~CDisk();
virtual void print();
void AddPartition(int size, const string & dsc);
static const int MAGNETIC = 0;
static const int SDD = 1;
private:
struct CPartition {
CPartition(int size, const string & dsc);
int div_size;
string disk;
};
int type;
int d_size;
vector<CPartition> ptts;
};
CDisk::CDisk(int tp, int size) {
type = tp;
d_size = size;
}
CDisk::CPartition::CPartition(int size, const string& dsc) {
div_size = size;
disk = dsc;
}
void CDisk::AddPartition(int size, const string& dsc) {
ptts.push_back(CPartition(size, dsc));
}
int main(int argc, char** argv) {
CDisk disk(CDisk::SDD, 5000);
disk.AddPartition(500, "disk1");
CPart *disk2 = new CDisk(disk);
delete disk2;
return 0;
}
When I run this code with valgrind, it says there are memory leaks and the number of bytes lost is equal to the number of items in vector ptts * size of CPartition. So I am guessing I have to clean that vector somehow. I have tried that but to no avail.
You need to have virutal destructor in CPart
class CPart {
public:
virtual void print() = 0;
virtual ~CPart(){};
};
Otherwise you will get following scenario;
int main(int argc, char** argv) {
CDisk disk(CDisk::SDD, 5000);
disk.AddPartition(500, "disk1");
CPart *disk2 = new CDisk(disk);//CDisk created
delete disk2;//But here only CPart is deleted leaving CDisks data in memory
return 0;
}
You can use valgrind to very precisely isolate the origin of memory leaks by using additional leak check parameters, ie:
valgrind --leak-check=full ./a.out
As long as your code is compiled with debug symbols, valgrind will tell you exactly where the leak is coming from.
I dont think this part is really true;
struct CPartition {
CPartition(int size, const string & dsc);
int div_size;
string disk;
};
CDisk::CPartition::CPartition(int size, const string& dsc) {
div_size = size;
disk = dsc;
}
It is better to put struct CPartition out of your class definition and get rid of CDisk::CPartition::CPartition(int size, const string& dsc) i.e:
struct CPartition {
int div_size;
string disk;
};
To call div_size of an instance of CPartition you should do
instance_of_CPartition->div_size
For further, read structure tutorial.
I'm not sure if this will solve your question but this will solve another problem in your code.

Double astrisk syntax & Help calling member functions

I'm working a program where there's an Airline class. The Airline class contains a vairable to an array of dynamic Flight objects.
In the Airlines class I have (which can't be edited or changed, this was the header file given to me for the assignment):
//Airline.h
class Airline {
public:
Airline(); // default constructor
Airline(int capacity); // construct with capacity n
void cancel(int flightNum);
void add(Flight* flight);
Flight* find(int flightNum);
Flight* find(string dest);
int getSize();
private:
Flight **array; // dynamic array of pointers to flights
int capacity; // maximum number of flights
int size; // actual number of flights
void resize();
};
//Flight.h
class Flight {
public:
Flight();
// Default constructor
Flight(int fnum, string destination);
void reserveWindow();
void reserveAisle();
void reserveSeat(int row, char seat);
void setFlightNum(int fnum);
void setDestination(string dest);
int getFlightNum();
string getDest();
protected:
int flightNumber;
bool available[20][4]; //only four seat types per row; only 20 rows
string destination;
};
I'm trying to impliment one of the find methods in the class.
for that, I have:
Flight* Airline::find(int flightNum){
bool found = false;
for(int i = 0; i < size; i++){
if(array[i].getflightNum() == flightNum){
found = true;
return array[i];
}
}
if(!found)
return 0;
}
// Return pointer to flight with given number if present, otherwise
// return 0.
But it's saying that I need a class type when trying to call the getFlightNum() method. I don't really understand the error. Am I not calling the method correctly? What is the correct syntax?
Since you are dealing with pointers instead of actual objects, try this:
if(array[i]->getflightNum() == flightNum){ // Notice I am using -> instead of .
found = true;
return array[i];
}