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

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.

Related

Delete a vector without deleting the array

I'm trying to populate a vector of doubles in C++ and pass the associated array to Fortran. But I'm having trouble freeing the rest of the memory associated with the vector. I'd like to avoid copying. Here's what I have:
std::vector<double> *vec = new std::vector<double>();
(*vec).push_back(1.0);
(*vec).push_back(2.0);
*arr = (*vec).data(); //arr goes to Fortran
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
Update
I see that I didn't give enough information here. A couple things:
I'm actually calling a C++ function in Fortran using iso_c_binding
I don't know how large the vec needs to be. The vector class looks good for this situation
I might try Guillaume's suggestion eventually, but for now, I'm passing vec to the Fortran and calling another C++ function to delete it once I'm done with the data
You need to rethink your program design.
Somehow, somewhere, you need to keep an array alive while Fortran is using it. So whatever context you're using to access Fortran should probably be responsible for ownership of this array.
class fortran_context {
/*Blah blah blah whatever API you're using to access Fortran*/
void * arr;
std::vector<double> vec; //Don't allocate this as a pointer; makes no sense!
public:
fortran_context() {
arr = //Do whatever is necessary to setup Fortran stuff. I'm assuming your
//api has some kind of "get_array_pointer" function that you'll use.
}
~fortran_context() {
//Do the cleanup for the fortran stuff
}
//If you want to spend time figuring out a robust copy constructor, you may.
//Personally, I suspect it's better to just delete it, and make this object non-copyable.
fortran_context(fortran_context const&) = delete;
std::vector<double> & get_vector() {
return vec;
}
std::vector<double> const& get_vector() const {
return vec;
}
void assign_vector_to_array() {
*arr = vec.data();
}
void do_stuff_with_fortran() {
assign_vector_to_array();
//???
}
};
int main() {
fortran_context context;
auto & vec = context.get_vector();
vec.push_back(1.0);
vec.push_back(2.0);
context.do_stuff_with_fortran();
return 0;
} //Cleanup happens automatically due to correct implementation of ~fortran_context()
I've abstracted a lot of this because I don't know what API you're using to access Fortran, and I don't know what kind of work you're doing with this array. But this is, by far, the safest way to ensure that
The vector's allocated memory exists so long as you are doing stuff in Fortran
The memory associated with the vector will be cleaned up properly when you're done.
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
The library does not provide any built-in capability to do that. You have to do the bookkeeping work yourself.
Allocate memory for the data and copy data from the vector.
Send the data to FORTRAN.
Decide when it is safe to deallocate the data and then delete them.
// Fill up data in vec
std::vector<double> vec;
vec.push_back(1.0);
vec.push_back(2.0);
// Allocate memory for arr and copy the data from vec
double* arr = new double[vec.size()];
std::copy(vec.begin(), vec.end(), arr);
// use arr
// delete arr
delete [] arr;
What you are asking for is not possible. std::vector, being a well behaved template class will release the internals that it owns and manages when it is destroyed.
You will have to keep vector alive while you are using its contents, which makes perfect sense. Otherwise, you will have to make a copy.
Also, I don't see why you are allocating the vector on the heap, it doesn't seem needed at all.
How do I delete vec while keeping arr intact? Is there a way to nullify the pointer to arr in vec so that I can then delete vec?
You don't.
I think you misuse or misunderstood what vector is for. It is not meant to expose memory management of the underlying array, but to represent a dynamically sized array as a regular type.
If you need to explicitly manage memory, I'd suggest you to use std::unique_ptr<T[]>. Since unique pointers offers a way to manage memory and to release it's resource without deleting it, I think it's a good candidate to meet your needs.
auto arr = std::make_unique<double[]>(2);
arr[0] = 1.;
arr[1] = 2.;
auto data = arr.release();
// You have to manage `data` memory manually,
// since the unique pointer released it's resource.
// arr is null here
// data is a pointer to an array, must be deleted manually later.
delete[] data;

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.

Memory Leak, source: float** binsRowPtrs = new float *[_nbins];

How do I delete this properly?
float** binsRowPtrs = new float *[_nbins];
The items are not dynamic created with new.
float** binsRowPtrs = new float *[_nbins];
for (int i = 0; i < _nbins ;i++)
{
binsRowPtrs[i] = (float*) (bins[i].row(y).data);
}
How do i delete this properly[?]
Properly? You use RAII and let something else handle the deletion for you. Depending on what you're trying to do, you may want to use:
std::vector<std::vector<float>>: an array of arrays of floats;
std::vector<float*>: an array of non-owning pointers to floats (i.e. something else handles correct allocation and deallocation);
or maybe just std::vector<float>: an array of floats.
The rule is:
Call as many delete or delete[] respectively as new or new[] you used and on the exact same addresses.
So if you just called new on binRowPtrs then you just need to call delete binRowPtrs.
However, in the part of your code which you didn't show us, If you used dynamic allocation through new for each of the array elements then you need to loop through the array and call delete on each of the element as well.
Note that ideally,
In C++ You should use dynamic allocations only when you cannot avoid them &
If et all you must, never use raw pointers, always use RAII through smart pointers to avoid the explicit memory management(you already noticed the perils of doing so in your case).
This will clear those pointers:
delete [] binsRowPtrs;
But the actual data you are storing with bins won't be touched.

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.

How to handle passing runtime-sized arrays between classes in 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.