How to manage an array of pointers to objects? - c++

I have a problem with an array of pointers to objects :(..
I need to generate a dynamic vector of object and then return it in
order to manipulate it in another class. In the code below there is
Event class that is abstract and CarArrival that inherits from it and
can be instantiated.
Inside the class that generate and fill the array I have this function:
Event** EventGenerator::getEvents() {
Event* cars[EVENTS];
for (int i=0; i<EVENTS; i++) {
cars[i] = new CarArrival(generator->getNextNumber(8,(float)sqrt(0.4)));
}
sort(cars, cars+(EVENTS), Event::cmp);
return cars;
}
I invoke this function in onther class in this way:
Event** cars = generator->getEvents();
for(int i=0; i<EVENTS; i++) {
cout << i <<":" << (*cars)[i]->getScheduleTime() << endl;
}
after the print of the first element i get "Segmentation Fault".
I have read some things online and I understand that I mistake since (*cars) evaluates to a
pointer to the first element of the array, in fact I can print the first element and not the other, but I cannot figure out how to access every element of the array in the second class.
How can I face this?
Thanks to all,
Alberto

I'd suggest that you use a std::vector<Event*> instead. You'll save a lot of pain this way. It takes care of all the nasty memory management in the background, and you can easily push any number of items into it. The best part in your case is, that you can simply return a vector which is not safe with a normal array.
Also your Event* cars[EVENTS]; is declared locally in you function. After you have finished it, it ceases to exist, which might cause your Segfault. You'd have to dynamically allocate the array with new, but still, try it with std::vector, see the documentation here.
EDIT: Sample Usage:
std::vector<Event*> EventGenerator::getEvents() {
std::vector<Event*> cars;
for (int i=0; i<EVENTS; i++) {
cars.push_back(new CarArrival(generator->getNextNumber(8,(float)sqrt(0.4))));
}
sort(cars.begin(), cars.end(), Event::cmp);
return cars;
}
std::vector<Event*> cars = generator->getEvents();
for(int i=0; i<cars.size(); i++) {
cout << i <<":" << (*cars)[i]->getScheduleTime() << endl;
}

I believe the cleanest way to handle a dynamic vector of pointers to dynamically allocated objects is to use a boost::ptr_vector. It handles everything you need, including allocation of the space to store the pointers, and deletion of those pointers afterwards.

Wouldn't be better to return vector<Event*> or vector<shared_ptr<Event>> instead of raw pointers? This way you would gain:
Automation of the memory management
Dynamic array with built-in length instead of fixed one

As mentionned by Constantinuis, you are returning the value of a pointer to a memory location that is only valid in the scope of the getEvents() function (it's allocated on the stack). You're bound to get a segfault next time.
You probably want to allocate the memory for this array in the heap (using 'new' if my C++'s isn't too rusty), and then you'll have to deal with freeing the memory later.
http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter13.html

Related

Dynamically allocating an array of pointers to objects

Question:
I have a class called croba.
In my console application I have a menu in which I can choose different options. After I choose an option, a switch statement checks my input and executes the block I chose.
In one of the cases I want the program to dynamicly alocate an array of pointers to class objects of a unknown size (the user is asked to input the size of the array), the catch is that the user input and the array must be alocated in the "case" block, but the alocated array has to be accessed globally later in the code. I declared a pointer to object globally like this:
croba *arrayOfObjectsPtr = NULL;
And here is the "case" block:
case 3:{
int numberOfElements;
int indexNumber;
if(!arrayOfObjectsPtr){
do{
cout << endl << "How many linked lists? "; cin >> numberOfElements;
}while(numberOfElements < 1);
croba *arrayOfObjectsPtrLocal[numberOfElements];
for (int i = 0; i < numberOfElements; i++){
arrayOfObjectsPtrLocal[i] = new croba;
}
}else{
cout << endl << "The array is already alocated!" << endl;
}
arrayOfObjectsPtr = arrayOfObjectsPtrLocal;
break;
}
I'm trying to figure out if there is a way to declare a pointer to an array of pointers to class objects globally and then alocating it later (because the number of elements is not known before).
In C++, the best practice is to use std::vector, which is the dynamic array class of the standard library. It is much nicer to use than C-style arrays. In your case it would look like this: std::vector<croba *> arrayOfObjectsPtr. Be careful though, because you will have to manually delete the pointers in the vector before destruction, like so:
for (auto& obj : arrayOfObjectsPtr)
delete obj;
If you don't want to perform the cleanup manually, like above, use a vector of smart pointers, like std::unique_ptr.
If you still want to use the old C-style array (which is not recommended), then declare it this way:croba** arrayOfObjectsPtr = new croba*[numberOfElements]. As for the cleanup, you'll have to do this:
for (int i = 0; i < numberOfElements; ++i)
delete arrayOfObjectsPtr[i];
delete[] arrayOfObjectsPtr;

generate multidimensinal array instead of cout

I have this main function and i want to get an multidimensional array out of this to generate a graph instead of cout
int main(){
zoro z;
std:ifstream k("ggg.grf");
z.getfromstream(k);
for(int i =0 ; i < z.nnodes; i++){
edge_iteratore s = z.begin(i);
while(s != z.end(i)){
std:cout << "(" << (*s).height << "," << (*s).weight << ")" << std::endl;
++s;
}
}
return 0;
}
I' trying to get std::out to a function to generate a multidimensional array
so i have implemented this function to get an array,
int createarr(height,width){
int** ary = new int*[height];
for(int i = 0; i < height; ++i)
ary[i] = new int[weight];
}
but nothing works, how can i return an multidimensional array to use it in another function call instead of outputting it to the screen.
If height and weight are constexpr values you know at compile time, declare std::array<<std::array<int>, weight>, height>. This gets you locality of reference. If they are values you compute at runtime or that could vary, use vector<vector<int>>(height) and initialize each row. Then the compiler takes care of freeing the memory for you. If only one is fixed, you can also do a vector of arrays or an array of vectors.
It’s unfortunate that, because of the legacy char** argv interface of main(), every beginning C and C++ programmer thinks that’s how you do a two-dimensional array. A ragged array like that is almost never what you really want. But if you do, use std::vector to manage the memory for you.
The problem with your createarr() as written is that it doesn’t return any array pointer, but RAII is more likely what you want. And if you do have a sparse matrix that would benefit from raggedness, you can use a format like Compressed Sparse Row.
You need to return a pointer to the created array.
But you'll need to somehow deal with the fact that this is dynamically allocated memory, ie, you need to release it when you're done.
And you'll need to somehow encapsulate the dimensions too, which then means it needs to be a struct.
When you finally get tired of dealing with memory leaks, and understand how pointers work, use std::vector like the other guy said.
In the meantime, don't try to implement complicated algorithms in C without understanding the basics first. Brush up hard on how pointers and arrays actually work, first.

Use of pointer to vector which involved the use of 'new'

I would like to create a vector of pointers to struct
vector<myStruct*> vec
For elements in the vector, not all of them contain data. Some of them may point to NULL.
So, should I create space by new in each of the element first
for(int i = 0; vec.size() ;i++){
if (thisSpaceIsValid(i))
vec.at(i) = new myStruct;
else
vect.at(i) = NULL;
}
The problem comes:
-If I use new for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector(vec here)?
-If later I use delete to free the memory, would the problem of speed still bother me?
If I use "new" for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector("vec" here)?
You can do that.
Let's say the size of your vector is M and you only need N of those elements to have pointers to objects and other elements are null pointers. You can use:
myStruct* objects = new myStruct[N];
and then, use:
for(int i = 0, j = 0; vec.size(); i++)
{
if (thisSpaceIsValid(i))
{
if ( j == N )
{
// Error. Do something.
}
else
{
vec[i] = objects+j;
++j;
}
}
else
{
vect[i] = NULL;
}
}
You have to now make sure that you are able to keep track of the value of objeccts so you can safely deallocate the memory by using
delete [] objects;
PS
There might be a better and more elegant solution to your problem. It will be worth your while to spend a bit more time thinking over that.
EDIT:
After reading the question again, it seems I misunderstood the question. So here is an edited answer.
If you only need to execute the code during some kind of initialization phase, you can create all the instances of myStruct in an array and then just point to those from the vector as already proposed by R Sahu. Note that the solution requires you to create and delete all instances at the same time.
However, if you execute this code several times and/or don't know exactly how many myStruct instances you will need, you could overwrite new and delete for the struct and handle memory allocation yourself.
See Callling object constructor/destructor with a custom allocator for an example of this. See the answer by Jerry Coffin.
BTW - you don't need vec.at(i) as you are iterating from 0 to size. vec[i] is okay and should perform a better.
OLD ANSWER:
You can do
vector<myStruct*> vec(10000, nullptr);
to generate a vector with for instance 10000 elements all initialized to nullptr
After that you can fill the relevant elements with pointer to the struct.
For delete just
for (auto e : vec) delete e;
cause it is safe to do deleteon a nullptr
If you need a vector of pointers, and would like to avoid calling new, then firstly create a container of structs themselves, then assign pointers to the elements into your vec. Be careful with choosing the container of structs. If you use vector of structs, make sure to reserve all elements in advance, otherwise its elements may move to a different memory location when vector grows. Deque on the other hand guarantees its elements don't move.
Multiple small new and delete calls should be avoided if possible in c++ when performance matters a lot.
The more I think about it, the less I like #RSahu's solution. In particular, I feel memory management in this scenario would be a nightmare. Instead I suggest using a vector of unique_ptr's owning memory allocated via custom alloctor. I believe, sequential allocator would do.

Vector overwriting object pointers

Everytime I call this method, The information is overwritten. If I call this function with name = "greg" then it will cout greg, If I then input "carl" it will cout carlcarl. The constructor is empty, and group and _groups are declared in the header.
I've been stuck on this for about 6 hours and I'm at a loss. Can someone explain to me how to fix this? It's not shown, but "group" is an object pointer. I'm taking this as a college course and its pretty much self-taught, I have to follow strict instructions on what to use and what not to use. I can't use strings.
void GroupDB::addGroup(char* name)
{
group = new GroupInfo(name, _nextGid++);
_groups.push_back(group);
for(int i = 0; i < _size; i++)
{
cout << (*_groups.at(i)).getGroupName();
}
_size++;
}
It sound's like you're storing the name pointer itself, which points to a temporary array that's invalidated at some point after this function returns. Instead, you want to store a more persistent copy of the string data. Use std::string not char* to store strings. If you "can't use strings" as a condition of the exercise, then you'll need to allocate an array to store the string data in, just as std::string would.
In general, don't use pointers unless you really need to. I doubt you want to be messing around with new here, but should rather store GroupInfo objects directly in the vector (or whatever _groups is).

Assigning dynamically allocated array of pointers

Having a lot of trouble with this after sifting through many posts on here. Everything compiles but I get a crash right here during this function which should be dynamically allocating the addresses of one array into this array of pointers. I see one or two memory addresses posted so I'm not sure why it would be crashing during the middle of this.
string *copyArray(string ptrArray[],int sizeArray)
{
string **dynamString = new string*[sizeArray];
int i;
for (i=0;i<=sizeArray;++i)
{
(*dynamString[i]) = ptrArray[i];
cout << dynamString[i];
}
return *dynamString;
}
from main I have:
string *arrPtr;
and the function call
arrPtr = copyArray(arrayOfStrings, arraySize);
for (i=0;i<=sizeArray;++i)
accesses an element behind the array yielding an undefined behavior. Elements are indexed from 0 to sizeArray - 1. Another problem is that you allocate the array of pointers:
string **dynamString = new string*[sizeArray];
and then you are derefencing these pointers although they do not point to any object yet:
(*dynamString[i]) = ptrArray[i];
which also causes an undefined behavior. In case you wanted to create a deep copy, you should allocate the memory for every object as well:
for (i = 0; i < sizeArray; ++i)
{
dynamString[i] = new std::string(ptrArray[i]);
cout << *dynamString[i];
}
However you should avoid using C-style arrays always when it is possible and prefer STL containers instead. In this case it could be neat std::vector<std::string> and its constructor that would do the same than your function (just in safer and more reasonable manner with no possible memory leaks):
std::vector<std::string> myStrings(arrayOfStrings, arrayOfStrings + arraySize);
ok I fixed it here. My pointer syntax was incorrect. Here is the correct syntax.
dynamString[i] = &ptrArray[i];