How to handle passing runtime-sized arrays between classes in C++ - c++

Right now I have a simple class that handles the parsing of XML files into ints that are useful to me. Looks something like this:
int* DataParser::getInts(){
*objectNumbers = new int[getSize()];
for (int i=0;i<getSize();i++){
objectNumbers[i]=activeNode->GetNextChild()->GetContent();
}
return objectNumbers;
}
In the main part of the program, I receive this by doing:
int* numbers= data->getInts();
///Do things to numbers[]
delete numbers;
Everything works fine until the delete command, which crashes everything. What is the proper way of doing this?

Part of the problem is that you are not pairing new[] with delete[]. This probably isn't the root of your bug here but you should get in the habbit of doing this.
The bug is almost certainly related to the code that you left commented out. Can you add some more context there so we can see what you're doing with the numbers value?
In general, I find it's much easier to use a vector for this type of problem. It takes the memory management out of the equation and has the added benefit of storing the size with the dynamic memory.
void DataParser::getInts(std::vector<int>& objectNumbers){
for (int i=0;i<getSize();i++){
objectNumbers.push_back(activeNode->GetNextChild()->GetContent());
}
}
...
std::vector<int> numbers;
data.getInts(numbers);

You need to
delete [] numbers;
The rules is whenever you
ptr = new Type[...];
make sure you
delete [] ptr;
instead of the regular
delete ptr;
which will result in undefined behavior (thanks Neil Butterworth) and is intended for deletion of a single instance where ptr points, not an array.

The following line:
*objectNumbers = new int[getSize()];
What does it do? If you are returning objectNumbers, this is a pointer to int, and you should really be doing:
objectNumbers = new int[getSize()];
Anyway, C++ gives you collections (vector, list etc) -- I'd have used one of those instead of a plain array. As noted elsewhere it is important to match your new with a delete and a new [] with a delete [].
Passing arrays around isn't good design -- you are making the implementation public. Try to pass iterators to the begining and end of the array/collection/sequence of ints instead following the STL design.

simply use a std::vector instead;
std::vector<int> DataParser::getInts(){
std::vector<int> objectNumbers(getSize());
for (int i=0;i<getSize();i++){
objectNumbers[i]=activeNode->GetNextChild()->GetContent();
}
return objectNumbers;
}

You will quickly run into trouble and maintenance issues. Consider using std::vector, this is the proper way to do it.

Related

Better way to store the address and value of a pointer, and reuse that same pointer variable without using dynamic memory allocation

Sorry if this question is already answered somewhere else, but I've been searching for a couple days and haven't been able to find exactly what I'm looking for.
I was wondering what a safer/cleaner way is to store a pointer (keep the address and value the same and store in some container) and reuse that same pointer variable.
Currently, I'm just using dynamic memory allocation and manually deleting it later on, but I was wondering if there is a better way to do this (I'll elaborate more after the code, since it may be easier to understand what I'm asking for then).
I attached some sample code below with what I'm talking about, and how I am currently doing it (please bear with me on any glaring mistakes, I'm still learning C++):
struct MyStruct{
double* arr;
MyStruct* parent_struct;
};
MyStruct* first_struct = new MyStruct;
first_struct->arr = some_array;
first_struct->parent_struct = nullptr;
std::vector<MyStruct*>* my_vector = new std::vector<MyStruct*>();
my_vector->push_back(first_struct);
double* temp_array;
MyStruct* temp_struct;
MyStruct* previous_struct;
for (i=0; i<num_iterations; i++){
temp_array = new double[sizeofarray];
assign_some_values(temp_array);
assign_struct_some_values(previous_struct);
if (some_condition(temp_array)){
temp_struct = new MyStruct;
temp_struct->arr = temp_array;
temp_struct->parent_struct = previous_struct;
my_vector->push_back(temp_struct);
} else{
delete [] temp_array;
}
}
... use values in my_vector ...
for (j=0; j<my_vector.size(); j++){
delete [] (*my_vector)[j]->arr;
delete (*my_vector)[j];
}
delete my_vector;
The main thing is, what alternative to the dynamically allocated arrays/structures can I use?
Please keep in mind that I would like to try to keep the address and values the same once they are added to my_vector, if at all possible (due to some requirements with the code I'm using). I feel like there is a much better way to do this without dynamic memory allocation, or so many pointers (like using smart pointers, std::array, etc), but I haven't been able to properly get any of the other methods to work.
When I try using smart pointers, I can't seem to get the custom deleter to work properly for the structures.
And when using a container (like std::vector) for the arr variables instead of double*, they keep getting deallocated (or I'm accidentally changing the address/values somehow) before the for loop is finished.

i have trouble assigning a vector to another vector. The program crashes

This is a shortened version of my actual code. This doesn't run too.
The line
tempPurchaseAndID[0] = tempPurchase;
causes the crash.
#include<vector>
#include<iostream>
using namespace std;
int main()
{
string* strTempPurchase = new string("", "");
string* tempOneID = new string("", "");
vector<string> temp;//if category name exists in his purchase
vector<string*/*size of two*/> tempPurchase;
vector<string*/*size of two*/> oneID;// vector for one id
vector<string*>* tempPurchaseAndID{};
tempOneID[0] = "2222";
oneID.push_back(tempOneID);
strTempPurchase[0] ="milk";
strTempPurchase[1] = "3";
tempPurchase.push_back(strTempPurchase);
tempPurchaseAndID[0] = tempPurchase;
tempPurchaseAndID[1] = oneID;
std::cin.get();
return 0;
}
Can someone see the problem and suggest a solution?
Thanks in advance.
P.S. I need the pointers for other things so i can't delete the pointers
As already pointed out, your problems start with pointers.
Firstly vector<string*>* tempPurchaseAndID{}; is not a vector but a null-pointer. Deferencing the null-pointer with tempPurchaseAndID[0] leads to a segfault.
It would be better to use just a vector, not a pointer to a vector:
vector<vector<string*> > tempPurchaseAndID;
But even now, your program would still crash in the same line but this time because of another reason: tempPurchaseAndID would have 0-length and there is no element with index 0 in it! So it is better to use push_back, adding elements to the vector at the end:
tempPurchaseAndID.push_back(tempPurchase);
tempPurchaseAndID.push_back(oneID);
Try to reduce the usage of the pointers - they are a source for a lot of errors and bugs.
std::vector supports the assignment operator already, same for std::string.
I don't see any reason why you are messing with pointers here. Copying pointers won't give you what you probably want to achieve.
You're moving passed the first string and attempting to write to a string that just isn't there here:
strTempPurchase[0] ="milk";
strTempPurchase[1] = "3";
Then you do something similar here, with the added problem that you never actually create an instance of strTempPurchase:
tempPurchaseAndID[0] = tempPurchase;
tempPurchaseAndID[1] = oneID;
Also note that handling vectors through pointers is not ideal. If you resize the vector (using push_back, for example) the vector can move its data to another location, thus invalidating your pointers.

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.

How to demonstrate memory error using arrays in C++

I'm trying to think of a method demonstrating a kind of memory error using Arrays and C++, that is hard to detect. The purpose is to motivate the usage of STL vector<> in combination with iterators.
Edit: The accepted answer is the answer i used to explain the advantages / disadvantages. I also used: this
Improperly pairing new/delete and new[]/delete[].
For example, using:
int *array = new int[5];
delete array;
instead of:
int *array = new int[5];
delete [] array;
And while the c++ standard doesn't allow for it, some compilers support stack allocating an array:
int stack_allocated_buffer[size_at_runtime];
This could be the unintended side effect of scoping rules (e.g constant shadowed by a member variable)... and it works until someone passes 'size_at_runtime' too large and blows out the stack. Then lame errors ensue.
A memory leak? IMO, vector in combination with iterators doesn't particularly protect you from errors, such as going out of bounds or generally using an invalidated iterator (unless you have VC++ with iterator debugging); rather it is convenient because it implements a dynamically resizable array for you and takes care of memory management (NB! helps make your code more exception-safe).
void foo(const char* zzz)
{
int* arr = new int[size];
std::string s = zzz;
//...
delete[] arr;
}
Above can leak if an exception occurs (e.g when creating the string). Not with a vector.
Vector also makes it easier to reason about code because of its value semantics.
int* arr = new int[size];
int* second_ref = arr;
//...
delete [] arr;
arr = 0; //play it safe :)
//...
second_ref[x] = y;
//...
delete [] second_ref;
But perhaps a vector doesn't automatically satisfy 100% of dynamic array use cases. (For example, there's also boost::shared_array and the to-be std::unique_ptr<T[]>)
I think the utility of std::vector really shows when you need dynamic arrays.
Make one example using std::vector. Then one example using an array to realloc. I think it speaks for itself.
One obvious:
for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
destination_array[i] = whatever(i);
versus
for (i = 0; i < NUMBER_OF_ELEMENTS; ++i)
destination_vector.push_back(whatever(i));
pointing out that you know the second works, but whether the first works depends on how destination_array was defined.
void Fn()
{
int *p = new int[256];
if ( p != NULL )
{
if ( !InitIntArray( p, 256 ) )
{
// Log error
return;
}
delete[] p;
}
}
You wouldn't BELIEVE how often I see that. A classic example of where any form of RAII is useful ...
I would think the basic simplicity of using vectors instead of dynamic arrays is already convincing.
You don't have to remember to delete your memory...which is not so simple since attempts to delete it might be bypassed by exceptions and whatnot.
If you want to do dynamic arrays yourself, the safest way to do it in C++ is to wrap them in a class and use RAII. But vectors do that for you. That's kind of the point, actually.
Resizing is done for you.
If you need to support arbitrary types, you don't have to do any extra work.
A lot of algorithms are provided which are designed to handle containers, both included and by other users.
You can still use functions that need arrays by passing the vector's underlying array if necessary; The memory is guaranteed to be contiguous by the standard, except with vector<bool> (google says as of 2003, see 23.2.4./1 of the spec).
Using an array yourself is probably bad practice in general, since you will be re-inventing the wheel...and your implementation will almost definitely be much worse than the existing one...and harder for other people to use, since they know about vector but not your weird thing.
With a dynamic array, you need to keep track of the size yourself, grow it when you want to insert new elements, delete it when it is no longer needed...this is extra work.
Oh, and a warning: vector<bool> is a dirty rotten hack and a classic example of premature optimization.
Why don't you motivate it based on the algorithms that the STL provides?
In raw array, operator[] (if I may call so) is susceptible to index-out-of-bound problem. With vector it is not (There is at least a run time exception).
Sorry, I did not read the question carefully enough. index-out-of-bound is a problem, but not a memory error.

Problems Expanding an Array in C++

I'm writing a simulation for class, and part of it involves the reproduction of organisms. My organisms are kept in an array, and I need to increase the size of the array when they reproduce. Because I have multiple classes for multiple organisms, I used a template:
template <class orgType>
void expandarray(orgType* oldarray, int& numitems, int reproductioncount)
{
orgType *newarray = new orgType[numitems+reproductioncount];
for (int i=0; i<numitems; i++) {
newarray[i] = oldarray[i];
}
numitems += reproductioncount;
delete[] oldarray;
oldarray = newarray;
newarray = NULL;
}
However, this template seems to be somehow corrupting my data. I can run the program fine without reproduction (commenting out the calls to expandarray), but calling this function causes my program to crash. The program does not crash DURING the expandarray function, but crashes on access violation later on.
I've written functions to expand an array hundreds of times, and I have no idea what I screwed up this time. Is there something blatantly wrong in my function? Does it look right to you?
EDIT: Thanks for everyone's help. I can't believe I missed something so obvious. In response to using std::vector: we haven't discussed it in class yet, and as silly as it seems, I need to write code using the methods we've been taught.
You need to pass oldarray as a reference: orgType *& oldarray. The way it's currently written, the function will delete the caller's array but will not give it the newly allocated one, causing the crash.
Better yet, use std::vector instead of reimplementing it.
The C++ standard library already has functionality written to do this.
Use the std::vector container.
Looks like you are modifying the pointer oldarray to point to the new array, but remember in the function that's just a copy and won't affect the variable you passed in. You probably need to pass a reference to a pointer if you want to do it this way.
And indeed, std::vector does this for you anyway