Adding dynamically allocated objects to array of object pointers - c++

I am trying to write a class function that can be called to dynamically create a new derived object and add that object to a dynamically allocated array that stores pointers to objects of the base class. If I run the function twice, I can access objectAry[0], but accessing objectAry[1] gives me read access violations. Can anyone tell me why this isn't storing the objects appropriately?
The objectAry was dynamically allocated with space for 10 objects, so there is room in position 1. This occurs even when newObject() is only called twice.
//Array definition (outside of function):
Base* objectAry;
objectAry = new Derived[10]
//Function in question:
void Derived::newObject()
{
Derived* tempObject = NULL;
tempObject = new Derived;
objectAry[numObjects] = *tempObject;
numObjects++;
delete tempObject;
tempObject = NULL;
}
When running a simple function to return one of the derived object's member variables:
Exception thrown: read access violation.
this->objectAry+1-> was 0x1.
Clearly I'm storing this incorrectly, but I'm not sure how to get this working.

First, in reference to:
//Array definition (outside of function):
Base* objectAry;
objectAry = new Derived[10];
A pointer to Base is allocated, but assigned a const pointer to the array of class Derived. This does not cause the fault, but sets up the subsequent code to fail.
In reference to the following statement,
objectAry[numObjects] = *tempObject;
the compiler views objectAry as an array of class Base. The sizeof(Base) is different than sizeof(Derived), which leads to an error in the determining
the pointer to the index within the dynamic array of class Derived. When the memory, within the array is modified with an improper offset, it is only a matter of time until a memory fault is generated with anything other than a trivial example.
In the following code, a context was created in a manner to reproduce the memory fault within the question. In the comments, you will see where the assignment was replaced with one that uses a dynamic_cast operation. The dynamic_cast now allows the index offsets to be correctly computed. Further, note the use of the dynamic_cast operations throughout, and the handling of the assignment operator. Caution is advised when using base pointers in this manner. See "Caution:" note at the end.
#include <iostream>
using namespace std;
class Base;
class Base{
public:
Base(){}
Base& operator=(Base& src){
copy_like_objects(this, &src);
return *this;
}
virtual void copy_like_objects(Base* dst, Base* src) = 0;
virtual ~Base(){};
};
class Derived : public Base{
public:
static const int objectAryLength = 10;
static int numObjects;
static Base* objectAry;
Derived();
~Derived(){};
static void newObject();
int data;
void copy_like_objects(Base *dst, Base *src){
*dynamic_cast<Derived*>(dst) = *dynamic_cast<Derived*>(src);
}
Derived& operator=(Derived& src){
data = src.data;
return *this;
}
static void allocate();
static void deallocate();
};
Derived :: Derived(){
data = -1;
}
void Derived :: allocate(){
if(objectAry == nullptr){
objectAry = new Derived[Derived :: objectAryLength];
}
for(int i = 0; i < Derived::objectAryLength; i++){ dynamic_cast<Derived*>(objectAry)[i].data = 0;}
}
void Derived :: deallocate(){
if(objectAry != nullptr){
delete[] dynamic_cast<Derived*>(objectAry);
objectAry = nullptr;
}
}
void Derived::newObject(){
Derived* tempObject = nullptr;
tempObject = new Derived; // The debugger may not step through
// the default constructor, which is called.
// tempObject = new Derived(); // Debugger steps through default constructor.
// At the time of this writing, in the commented statement
// the compiler seems to be computing the sizeof class base
// to evaluated the index into an array of the supposedly
// allocated array of bases classes instead of flagging as an error.
// As a result, The derived class copies data on a missaligned
// Derived object allocation, currupts the array of objects, which then
// is the cause of a subsequent memory fault.
//
// objectAry[numObjects] = *tempObject;
// Using the cast below, fixes the alignment issues and avoid a memory fault.
dynamic_cast<Derived*>(objectAry)[numObjects] = *tempObject;
numObjects++;
delete tempObject;
tempObject = nullptr;
}
int Derived::numObjects = 0;
Base* Derived::objectAry = 0;
int main(int argc, char **argv) {
Derived :: allocate();
for(int i = 0; i < Derived::objectAryLength; i++){
cout << (dynamic_cast<Derived*>(Derived::objectAry))[i].data << " : " ;
} cout << endl;
Derived::newObject();
Derived::newObject();
for(int i = 0; i < Derived::objectAryLength; i++){
cout << (dynamic_cast<Derived*>(Derived::objectAry))[i].data << " : " ;
} cout << endl;
Derived :: deallocate();
return 0;
}
Caution: In general, when base class pointers are used in this manner, one will create a situation where there is an high likelihood of making an error that causes a memory fault or an exception during a dynamic_cast<>, which can easily show up in run time edge cases. To resolve this issue, consider redesigning and start with:
Base** objectAry;
objectAry = new Base*[10];
The logic to manage the list can be placed in the Base class without knowledge of which derivations are stored within the list. This approach leverages the polymorphic nature of C++ and will simplify coding with improved reliability. This approach will allow any derived class of Base to be managed within the list. It is important to properly manage the allocation and deallocation of derived objects within the list management logic.

Related

It is legal this approach for create a local variable in C++

I'm new to C++ and try to understand how to create and use a class in C++.
For this I have the following code:
class MyClass
{
public:
MyClass()
{
_num = 0;
_name = "";
}
MyClass(MyClass* pMyClass)
{
_num = pMyClass->_num;
_name = pMyClass->_name;
}
void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
void SetValues(int number, std::string name)
{
_num = number;
_name = name;
}
private:
int _num;
std::string _name;
};
int main()
{
std::vector<MyClass*> myClassArray;
MyClass myLocalObject = new MyClass();
for (int i = 0; i < 3; i++)
{
myLocalObject.SetValues(i, "test");
myClassArray.push_back(new MyClass(myLocalObject));
}
myClassArray[1]->PrintValues();
// use myClassArray further
}
I get a similar example from the internet and try to understand it.
My intentions is to populate myClassArray with new class objects.
If I compile the code above using VisualStudio 2022 I get no errors, but I'm not sure it doesn't produce memory leaks or if there is a faster and simple approach.
Especially I do not understand the following line:
MyClass myLocalObject = new MyClass();
myLocalObject is created on the stack but is initialized with a heap value (because of the new). If new operator is used where should delete must apply?
Thank you for any suggestions!
You have a memory leak at MyClass myLocalObject = new MyClass();, since the dynamically-allocated object is used to converting-construct the new myLocalObject (this was almost but not quite a copy constructor) and then the pointer is lost.
You also didn't show the code using the vector, but if it doesn't delete the pointers inside, you will have more memory leaks.
There's no reason to have an almost-copy-constructor; the compiler has provided you with a better real copy-constructor.
The faster and simpler approach is to recognize that this code doesn't need pointers at all.
class MyClass
{
public:
MyClass()
: _num(), _name() // initialize is better than assignment
{
//_num = 0;
//_name = "";
}
// compiler provides a copy constructor taking const MyClass&
//MyClass(MyClass* pMyClass)
//{
// _num = pMyClass->_num;
// _name = pMyClass->_name;
//}
void PrintValues() { std::cout << _name << ":" << _num << std::endl; }
void SetValues(int number, std::string name)
{
_num = number;
_name = name;
}
private:
int _num;
std::string _name;
};
int main()
{
std::vector<MyClass> myClassArray; // not a pointer
MyClass myLocalObject; // = new MyClass(); // why copy a default instance when you can just default initialize?
for (int i = 0; i < 3; i++)
{
myLocalObject.SetValues(i, "test"); // works just as before
myClassArray.push_back(/*new MyClass*/(myLocalObject)); // don't need a pointer, vector knows how to copy objects
// also, this was using the "real" copy-constructor, not the conversion from pointer
}
myClassArray[1].PrintValues(); // instead of ->
// use myClassArray further
}
for cases where a pointer is necessary, for example polymorphism, use a smart pointer:
std::vector<std::unique_ptr<MyClass>> myClassArray; // smart pointer
myClassArray.push_back(make_unique<MyDerivedClass>(stuff));
std::unique_ptr will automatically free the object when it is removed from the vector (unless you explicitly move it out), avoiding the need to remember to delete.
There are basically 2 ways to instantiate objects of classes.
Dynamic allocation (on heap)
MyClass* myLocalObject = new MyClass(); // dynamically allocates memory and assigns memory address to myLocalObject
Example for your loop:
class MyClass
{
private:
int _num;
std::string _name;
public:
// let's add an additional constuctor having default values
// that makes it easier later on
// if parameters are passed, they are used, or the defalt values, if not
// can call it like MyClass(), MyClass(123), or MyClass(456,"hello")
// you might want to pass larger data as reference, to avoid copying it
MyClass(int num=0, std::string name = "some default text")
: _num(num), _name(name)
{}
};
std::vector<MyClass*> myClassArray; // your array of pointers
for (int i = 0; i < 3; i++)
myClassArray.push_back(new MyClass(i, "test"));
// delete
for (auto& pointerToElement : myClassArray) // get a reference to each element (which is a pointer)
delete pointerToElement; // delete element (call's destructor if defined)
In that case you must delete myLocalObject; or you get a memory leak.
Instead of dealing with raw pointers, especially when new to C++, I recommend to use smart pointers, that deal with memory management for you.
Automatic allocation (on stack when possible)
MyClass myLocalObject = MyClass(); // automatically allocates memory and creates myLocalObject
This happens usually on stack (if possible). That's much faster and you don't have to deal with dynamic memory management
Example for your loop:
std::vector<MyClass> myClassArray; // now "containg" the memory of objects itself
for (int i = 0; i < 3; i++)
{
myClassArray.emplace_back(i, "test"); // we use emplace_back instead to construct instances of type MyClass directly into the array
}
// no deletion required here
// destructors of each element will be called (if defined) when myClassArray is deleted automatically when out of scope
There are other ways, like dynamic stack allocation and other black magic, but recommend to focus on "the standard".
In case of dealing with large amounts of data, you might want to use std::vector::reserve. In combination with automatic/stack allocation that helps to speed up a lot by limiting memory allocations to 1 at all instead of 1 per element.
Hope that helps :-)

Order of destructors

I have these kind of classes:
Game:
class Game {
private:
BoardField*** m_board_fields;
public:
Game() {
m_board_fields = new BoardField**[8];
for (int i = 0; i < 8; i++) {
m_board_fields[i] = new BoardField*[8];
}
}
Game::~Game() {
for (int i = 0; i < 8; i++) {
for (int j = 0; i < 8; j++) {
delete m_board_fields[i][j];
}
delete[] m_board_fields[i];
}
delete[] m_board_fields;
}
}
BoardField:
class BoardField {
private:
ChessPiece* m_piece;
....
public:
BoardField::~BoardField() {
delete m_piece;
}
}
And on the close of the program I get error in ~BordField:
Exception thrown: read access violation.
this was 0xFDFDFDFD.
Did I made my destructors incorrect? What is the best way to clear memory from multidimensional array ?
There is are two fundamental flaws in your design:
there is no clear ownership of the BoardFields: someone create it, someone else deletes it. It can work if you're very cautious but it's error prone.
you do not ensure the rule of 3 (or better 5): if you have any piece of code where you create a copy of either your Game or a of any BoardField the first object that gets destroyed will delete the m_piece pointer, and when the second object gets destroyed, it'll try to delete a second time the same pointer, which is UB.
There is a third important issue: you're over-using raw pointers:
if m_board_fields is a 2d array of fixed size, make it a fixed size array (aka BoardField* m_board_fields[8][8]). If you want to keep its size dynamic, use vectors.
a cell of m_board_field could be a pointer if there's some polymorphism expected. But this seems not the case here, as obviously ChessPiece is the polymorphic class. So better use plain fields instead of pointers (aka BoardField m_board_fields[8][8]).
Finally, instead of using raw pointer to ChessPiece, better use a shared_ptr<ChessPiece> : you don't have to worry about shallow pointer copies and double delete; the shared_ptr will take care of itself and destroy the object if it's no longer used.

Using "new" operator to create objects in an array C++

In Java
nodes[i] = new Object();
is a valid statement
What is the C++ equivalent?
EDIT:
It seems I am not providing enough context.
I was reading some Java code implementing a QuadTree, and I was curious on how I could rewrite that segment of code in C++.
I did not need a direct equivalent, I wanted something that essentially means the same thing.
In Java, you can do things like
class A
{
public A (someObject o);
}
main method:
A aObject = new A(new someObject());
or in a loop:
for(int i = 0; i < arr.length; i++)
{
arr[i] = new someObject();
}
In C++ I know you can do:
std::vector<someObject*> arr;
someObject* o = new someObject;
arr.push_back(o);
Is there something similar to java's new Object(); style of creating objects without explicit declaration in C++?
Java is a garbage-collected language, while C++ is not. The languages differ so much on what the code above "means", that it is not trivial to quote a direct "equivalent".
A similar method of implementing this in C++, would be to use shared_ptr, which is not garbage collected, but instead ensures that the underlying objects are destroyed when all references to them go out of scope.
#include <vector>
#include <memory>
using namespace std;
class Object
{
};
int main()
{
std::vector<std::shared_ptr<Object>> nodes(1);
nodes[0] = std::make_shared<Object>();
return 0;
}
There are actually a few aspects regarding your question, depending on what do you really mean by the piece of code you posted.
1. Explicit command
Yes, this command can be issued in C++, for example:
class Object
{
};
int main(int argc, char * argv[])
{
std::vector<Object *> nodes;
nodes.push_back(nullptr);
int i = 0;
nodes[i] = new Object();
// To prevent memory leaks
delete nodes[i];
}
2. Using generic base class, Object
C++ does not have a universal base class such as Object in Java or C#. You have to instantiate something to put it into the array or std::vector. (read more: Root base class in C++)
If you really need such class in your code, you can simply define one, for example:
class Object
{
virtual std::string ToString()
{
return "Object";
}
virtual int GetHashCode()
{
return (int)this;
}
virtual bool Equals(Object & other)
{
return this == &other;
}
};
3. Memory management
In C++ you can explicitly instantiate class at some point.
However, C++ does not have garbage collector working for the dynamic objects such as Java or C#. If you allocate memory explicitly using new operator, you have to delete allocated memory at some point.
On the other hand, C++ tries lately to catch up to high-level languages by providing a set of classes simplifying memory management, such as std::shared_ptr, std::weak_ptr or std::unique_ptr, for example:
class Object
{
};
int main(int argc, char * argv[])
{
std::vector<std::unique_ptr<Object>> nodes;
nodes.resize(1);
int i = 0;
nodes[i] = std::unique_ptr<Object>(new Object());
// nodes destructor will call std::unique_ptr<Object>
// destructor, which will eventually destroy instance
// of the Object class.
}
Read more here: What is a smart pointer and when should I use one?
4. Indexing arrays, classes
You can always use [] to index arrays. You may use [] to index class instances (such as std::vector) if class supports that (overloads [] operator).
int main(int argc, char * argv[])
{
// Statically allocated array
int test[5];
test[0] = 1;
// Dynamically allocated array
// This is useful if you work with
// some C libraries or simply (really)
// need to allocate a block of memory.
int * test2 = new int[5];
test2[0] = 1;
delete[test2];
// This is a lot more C++ way of keeping
// an array of items:
std::vector<int> test3;
test3.resize(1);
test3[0] = 1;
}

Different Destructor Types?

I have an object called a Chunk that holds a pointer to a b2Body. It does other important things, but i removed those for simplicity. Heads up, smart pointers won't work(I think), you'll see why.
class DChunk
{
public:
DChunk();
DChunk(const DChunk& old);
virtual ~DChunk();
virtual b2Body* getBody() const;
private:
b2Body* m_pBody;//pointer;
};
The question is, how to define when to delete the m_pBody object.
If I want to copy this object, like say there is a vector of these things and I push_back another, it will call the Copy Constructor, copy the memory address of m_pBody(thats what i want), and then delete the old one. If the Destructor on this object deletes m_pBody, that's obviously bad, because the new copy wont have a valid memory address, but if it doesn't delete it, then m_pBody will never be deleted, and it needs to be deleted when there are no more Chunks pointing at it.
The only correct way to delete the m_pBody object is to call m_pBody->GetWorld()->DestroyBody( m_pBody ); and thats not under my control, so smart pointers dont really work.
I was hoping there would be different types of destructors that get called appropriately, like when a copy has been made in a vector. Also, there should never be more than one Chunk associated with one b2Body, if that is helpful.
I will assume you have something like
vector<DChunck> myvec;
and you are worried about doing
obj=DChunk()
myvec.push_back(obj)
First of all (this is very beginner friendly approach, avoiding smart pointers or any C++11) there's something not quite correct about creating a container DChunk objects. That's because when you declare
vector<DChunk>
you are telling your vector that it will receive objects the size of DChunk.
However, since that class contains a pointer to an array, m_pBody (array's size will not be constant!), this approach will not be too "healthy" for C++.
Given this, you can do something else, sticking to your class design: create a container of pointers!
You can create
vector<DChunk*> myvec;
and if you want to add an object to that vector, you just do
DChunk *obj = new DChunk();
myvec.push_back(event);
since now the container is handling pointers, which can be juggled around without interfering with the objects content, avoiding the worries concerning a destructor.
Calling an object's method will now be, for example,
(*myvec[3]).getBody()
or (cleaner version)
myvec[3]->getBody()
Hope I addressed your question
You can also provide move constructor so that instead of copying, it would move stuff... Here's an example that I made some hours ago, because I had the same problem (I didn't know in what order would these constructors and when be called, also "&&" is move constructor):
A move constructor is similar to copy constructor. The difference is that in move constructor instead of copying values and stuff, you assign given object's pointers (not copy) and values to a new one (this->temp = OldClass.temp) and then make OldClass.temp = NULL; so that when the unavoidable destructor is called, it finds a NULL pointer and does not delete it.
#include <iostream>
#include <Windows.h>
class MyClass
{
public:
MyClass()
{
temp = new RECT();
ZeroMemory(temp, sizeof(RECT));
}
MyClass(int x, int y)
{
temp = new RECT();
ZeroMemory(temp, sizeof(RECT));
temp->left = x;
temp->top = y;
}
MyClass(MyClass &&OldClass)
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
temp = OldClass.temp;
OldClass.temp = NULL;
}
MyClass& operator=(MyClass &&OldClass)
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
temp = OldClass.temp;
OldClass.temp = NULL;
return *this;
}
MyClass(const MyClass &OldClass)
{
*temp = *OldClass.temp;
}
MyClass& operator=(const MyClass &OldClass)
{
*temp = *OldClass.temp;
return *this;
}
~MyClass()
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
}
void Print()
{
std::cout << temp << " " << temp->left << " " << temp->top << " " << temp->right << " " << temp->bottom << '\n';
}
private:
RECT *temp;
};
int main()
{
MyClass bla, cha(54, 48);
bla.Print();
cha.Print();
bla = MyClass(2, 2);
bla.Print();
bla = cha;
bla.Print();
cha = MyClass(54, 2);
cha.Print();
std::cin.get();
return 0;
}
In common, a proper memory management is non trivial task and no universal decision are existing. Some simple and common well-known methods are presented as "smart pointer" types in newest libraries (and you can also define them yourself (by copy known "standard definition")). But it also is not an completely universal :-)
And your question seems to be a question for a such universal solution.
Some other programming languages (java ... , not C++) advertise you to get rid of that problem (by the built-in methods of language implementations).
You write: "Also, there should never be more than one Chunk associated with one b2Body, if that is helpful." . And then the problem seems to disappear (because the Chunk cannot be copied at all). (?)

How to call virtual function of an object in C++ [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Overriding parent class’s function
I'm struggling with calling a virtual function in C++.
I'm not experienced in C++, I mainly use C# and Java so I might have some delusions, but bear with me.
I have to write a program where I have to avoid dynamic memory allocation if possible. I have made a class called List:
template <class T> class List {
public:
T items[maxListLength];
int length;
List() {
length = 0;
}
T get(int i) const {
if (i >= 0 && i < length) {
return items[i];
} else {
throw "Out of range!";
}
};
// set the value of an already existing element
void set(int i, T p) {
if (i >= 0 && i < length) {
items[i] = p;
} else {
throw "Out of range!";
}
}
// returns the index of the element
int add(T p) {
if (length >= maxListLength) {
throw "Too many points!";
}
items[length] = p;
return length++;
}
// removes and returns the last element;
T pop() {
if (length > 0) {
return items[--length];
} else {
throw "There is no element to remove!";
}
}
};
It just makes an array of the given type, and manages the length of it.
There is no need for dynamic memory allocation, I can just write:
List<Object> objects;
MyObject obj;
objects.add(obj);
MyObject inherits form Object. Object has a virtual function which is supposed to be overridden in MyObject:
struct Object {
virtual float method(const Input& input) {
return 0.0f;
}
};
struct MyObject: public Object {
virtual float method(const Input& input) {
return 1.0f;
}
};
I get the elements as:
objects.get(0).method(asdf);
The problem is that even though the first element is a MyObject, the Object's method function is called. I'm guessing there is something wrong with storing the object in an array of Objects without dynamically allocating memory for the MyObject, but I'm not sure.
Is there a way to call MyObject's method function? How? It's supposed to be a heterogeneous collection btw, so that's why the inheritance is there in the first place.
If there is no way to call the MyObject's method function, then how should I make my list in the first place?
Also I have no access to libraries outside of math.h and stdlib.h, so vector is not available for example.
You need to store pointers in the list. Try this:
List<Object*> objects;
Object *obj1 = new Object;
MyObject *obj2 = new MyObject;
Object *obj3 = new MyObject;
objects.add(obj1);
objects.add(obj2);
objects.add(obj3);
// This calls the implementation in Object class
objects.get(0)->method(asdf);
// This calls the implementation in MyObject class
objects.get(1)->method(asdf);
// This calls the implementation in MyObject class
// Polymorphism here
objects.get(2)->method(asdf);
Hope this helps.
When you do this:
objects.add(obj);
you are adding a copy of the Object part of the MyObject to the list, so it is no longer a MyObject.
You might be tempted to try doing this:
int add(T const &p) {
if (length >= maxListLength) {
throw "Too many points!";
}
items[length] = p; // now the problem is here
return length++;
}
but now the copy of the Object part of p happens during the assignment.
To make the list be heterogeneous, it is going to have to be a list of pointers, but you also wanted to avoid dynamic memory allocation. You can avoid dynamic memory allocation if you are careful:
Object obj1;
MyObject obj2;
List<Object*> object_ptrs;
object_ptrs.add(&obj1);
object_ptrs.add(&obj2);
 object_ptr.get(1)->method(input);
object_ptr.get(0)->method(input);
but again, you have to be very careful. The list is now pointing to the two objects on the stack. If you return from this function, those two objects will be destroyed. Note that I've purposefully put the list of object pointers after the objects, so that the list will get destroyed before the objects, so the list won't be left pointing to garbage. However, if you return a copy of the list, you would still have a problem.