I'm having a little trouble grasping some concepts with C++ arrays.
On my assignment, I did something like the code below. From what I can tell, this not only creates space on the heap for [size] Object1 objects, but also initializes all of them too. Can somebody explain what is exactly happening on the heap and stack here?
class Object1
{
Private:
int dummy;
Public:
Object1();
};
Object1::Object1()
{
dummy = 1;
}
class Foo
{
private:
Object1 * myObject;
public:
Foo(int size);
};
Foo::Foo(int size)
{
myObject = new Object1[size];
}
If Object1's constructor had taken a parameter, like in the code below, then what would happen differently on the stack and heap, if anything? I'm not sending any parameters into each instance of object1, so would it still initialize any object, or just create the space?
class Object1
{
Private:
int dummy;
Public:
Object1(int myInt);
};
Object1::Object1(int myInt)
{
dummy = myInt;
}
I also saw the code below somewhere. What is happening in this case, and how is it different than the cases above?
myclass *array[10];
for (int i = 0 ; i != 10 ; i++) {
array[i] = new myclass();
}
I've completed the assignment, but am just trying to make sure I understand what's happening behind the scenes.
Thank you in advance for taking the time to help!
If your class does not have a default constructor, you won't be able to use:
myObject = new Object1[size];
The difference between
myObject = new Object1[size];
and
myclass *array[10];
for (int i = 0 ; i != 10 ; i++) {
array[i] = new myclass();
}
The first one allocates size objects and stores the pointer to the array of objects in myObject.
The second one allocates 10 objects but there are 10 pointers. Each pointer points to only one dynamically allocated object.
Related
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 :-)
I have a headache. Is the following code snippet right? I would like to create an array of 19 B objects, which contains another array of X A objects. (X is variable, I mean that the As array could vary in length between the B objects)
Later on I would like to say something like B_obj[i].As[j].number = 0;
(i = [0-18], j = [0 - depends on the object])
Example:
class A
{
public:
A();
private:
char *arena;
size_t size;
int number;
};
A::A()
{
size = 5;
arena= (char *) malloc (size);
... some code ...
}
class B
{
private:
int counter;
A* As;
public:
B();
};
B::B()
{
counter = getMyNumber(); /* getMyNumber returns an individual ID */
As= (A*) malloc(counter * sizeof(A)));
}
B B_obj[19];
Is the memory correct allocated? Everything have to be setup, I am not allowed to alloc extra memory later on.
I would like to create an array of 19 B objects, which contains another array of X A objects.
class B {
std::vector<A> x;
public:
// your public interface here
};
B arr[19];
The solution becomes very simple when you use good RAII solutions like std::vector, because it does the memory management for you. Memory is allocated automatically, and you can use std::vector::reserve to allocate a certain number of A objects in the vector.
I'm trying to assign a node to a pointer along an array of pointers but it keeps telling me that my array was not declared in the scope. I'm totally confused on how or why so any help would be greatly beneficial! Thanks for taking the time to respond!
#include <iostream>
#include "book.h"
using namespace std;
class bookstore
{
private:
int amount = 5;
int counting = 0;
public:
bookstore()
{
bookstore *store;
store = new book*[amount];
for(int i = 0; i < amount; i++)
{
store[i] = NULL;
}
}
~bookstore(){ delete[] store; }
void addbook(string a,string b, string c, string d, string e)
{
if (counting == amount)
{
cout<<"Full House!"<<endl;
return;
}
store[counting] = new book(a,b,c,d,e);
counting++;
}
void print()
{
for(int i = 0; i < amount; i++)
{
cout<<store[i]->name<<" "<<store[i]->publisher<<" "<<store[i]->year<<" "<<store[i]->price<<" "<<store[i]->category<<endl;
}
}
};
Your pointer store is local to the default constructor. It looks like you're after a data member. Furthermore, you seem to be after an array of pointers. If so, you need bookstore needs to be a pointer to pointer:
class bookstore
{
private:
bookstore** store; // or bookstore* store
int amount = 5;
int counting = 0;
and fix the constructor to use that:
bookstore()
{
store = new book*[amount]; // or store = new book[amount]
....
Note that your class is attempting to manage dynamically allocated resources, so you will need to take care of the copy constructor and assignment operators (either make the class non-copyable and non-assignable, or implement them. The defaults are not acceptable. See the rule of three.) If you are really using an array of dynamically allocated pointers, then you need to fix your destructor too. Currently, it only deletes the array, but not the objects pointed at by the pointers in it.
The better solution would be to use a class that manages the resources for you and has the desired semantics. It is easier to have each class handle a single responsibility.
I am trying to implement my own class Alloc which will help in the dynamic allocation of objects..
I want to keep track of the number of allocated objects in my program. So, each time a new instance of an object is allocated, the counter increments by one and decrements when an object is destroyed. When my program shuts down, if the counter is not at zero, the object prints an error message to the screen and has the program hang until the user hits enter..
This is what I have so far.. I hope you guys can help me to implement this..
class Alloc{
static int counter;
public:
Alloc(){ counter++; };
Alloc(int *d, static int size, const Alloc& c){
d=(int *) malloc(size*sizeof(int));;
//d=new int[size];
Alloc *my_alloc;
//my_alloc = new Alloc[size]; //note that the type is a Myclass pointer
for(int i=0; i<size; i++){
my_alloc[i] = new Alloc[size];
}
//for(int i=0; i < size; i++){
// d[i]=c.d[i];
//}
}
~Alloc(){ counter--; }
};
I know a lot is missing so, I will appreciate help and fixing mistakes too..
Thanks!!!
d=(int *) malloc(size*sizeof(int));;
d=new int[size];
The second line here is overwriting the d pointer with a second allocation, so the memory allocated by malloc is being lost!
If you really want to do it this way you need to use placement new, i.e. something like
d=(int *) malloc(size*sizeof(int));;
e=new (d) int[size];
though the details are quite tricky to get right.
To just count the number of objects in your programme though, there is a much easier option. Implement a templated "mixin" which contains a static counter for each type. Something like
template <typename T>
struct countable
{
countable() { _count++; }
countable(const countable&) { _count++; }
~countable() { _count--; }
static int get_count() { return _count; }
private:
static int _count;
};
and then having your objects inherit from this, as in
class MyClass : countable<MyClass>
{
// whatever
};
It's simple, and easy to turn into a no-op for release builds.
the track of number of instances of class say Alloc can also be kept as
class Alloc
{
Public:
static int Coounter; // object counter
// Constructor
Alloc(){
Counter++;}
// Destructor
~Alloc()
{
Counter--;
}
};
Simple, easy to use and maintainable
Basically I want to create an array of objects with a size which is passed through from one class to another i.e.
Object * ArrayOfObjects = new Object[Size];
Whilst that creates an array successfully, it doesnt allow me to use constructors.
How can I create an array of my objects then define each object in the array?
Once you allocate memory for the array you can then assign to it by looping:
for (int i = 0; i < Size; ++i)
{
ArrayOfObjects[i] = Object( /* call the constructor */ );
}
Or you can use a vector to do the same but with more ease of use:
std::vector<Object> ArrayOfObjects = { Object(...), Object(...) };
What you're asking may not actually be the best thing to do - which would be to use something like std::vector or something, but under the hood what they're going to do is what your question asks about anyway.
Then you can either assign or placement new each entry:
for (size_t i = 0; i < Size; ++i)
{
// Option 1: create a temporary Object and copy it.
ArrayOfObjects[i] = Object(arg1, arg2, arg3);
// Option 2: use "placement new" to call the instructor on the memory.
new (ArrayOfObjects[i]) Object(arg1, arg2, arg3);
}
Once you allot memory, as you did. You initialize each object by traversing the array of objects
and call its constructor.
#include<iostream>
using namespace std;
class Obj
{
public:
Obj(){}
Obj(int i) : val(i)
{
cout<<"Initialized"<<endl;
}
int val;
};
int allot(int size)
{
Obj *x= new Obj[size];
for(int i=0;i<10;i++)
x[i]=Obj(i);
//process as you need
...
}