Unallocate large array - ocaml

I am curious if there is a way to delete and unallocate something in OCaml. For example, let us say I have an array initialized using:
let a = Array.make 10000 0;;
How do I "delete" a?
Thanks in advance.

The short answer is that values are deleted (by the garbage collector) when they can no longer be accessed.
If this definition of a is a global definition, it is always accessible. Hence it will never be deleted.
If, instead, this is a local definition in a function it will be deleted when the function returns (or possibly sooner if the last reference is before the end of the function).
In general, immutable global values won't ever be garbage collected. If you want this, you can use a mutable global value:
let a = ref (Array.make 10000 0)
When you no longer need a you can do this:
a := [| |]

Related

Is it valid to delete a lambda while executing it?

Is it allowed to delete a lambda object while executing the associated lambda function, as long as precautions are taken not to access any of the captured state after the deletion?
Consider the following example:
int main() {
int x = 1;
std::function<void()> d;
auto l = new auto([x, &d]() {
fmt::print("x is {}\n", x);
d();
fmt::print("I'm deleted\n");
});
d = [l](){ delete l; };
(*l)();
}
Here, the lambda pointed to by l deletes itself using a Rube Goldberg-like approach through the d function1. After the deletion it prints a fixed message which doesn't access any captured state.
Is it defined behavior?
1 I couldn't figure out a better way to break the circular dependency between the lambda code which needs to see something that points to itself: I'm open to better options.
There might not be an explicit specification for this in the standard.
Although not specified to be so, lambda types are "essentially" like special classes. Staying with this analogy, the question would be same as "Is it well defined to delete this;". The typical answer to that question is:
As long as you’re careful, it’s okay (not evil) for an object to commit suicide (delete this).
Here’s how I define “careful”:
You must be absolutely 100% positively sure that this object was allocated via new (not by new[], nor by placement new, nor a local object on the stack, nor a namespace-scope / global, nor a member of another object; but by plain ordinary new).
You must be absolutely 100% positively sure that your member function will be the last member function invoked on this object.
You must be absolutely 100% positively sure that the rest of your member function (after the delete this line) doesn’t touch any piece of this object (including calling any other member functions or touching any data members). This includes code that will run in destructors for any objects allocated on the stack that are still alive.
You must be absolutely 100% positively sure that no one even touches the this pointer itself after the delete this line. In other words, you must not examine it, compare it with another pointer, compare it with nullptr, print it, cast it, do anything with it.
To translate these points to lambdas, "call a member function" becomes "call the lambda", "any data members" becomes "any capture". Your example satisfies all of the points.

C++ references and exiting scoping

I'm getting to grips with references in C++ and I have a small query surrounding references & scoping, for this it's probably best to create an example:
Imagine I have a method in "BankDatabase.cpp" which takes a bank record by reference and adds it to a data structure (also by reference).
void AddRecord( BankRecord& bankRecord )
{
//Add record to data structure by reference
}
If I run a method like so:
void TestAddRecord( BankDatabase& bankDatabase )
{
BankRecord bankRecord { "John", "Doe", 9999 }
bankDatabase.AddRecord( bankRecord );
}
To my mind, "bankRecord" falls out of scope (as do its two strings and int) and is thus cleared from memory at the end of the "TestAddRecord" method, leaving "bankDatabase" pointing at some empty memory?
If so what's the general accepted standard / resolution to such a scenario? It seems a little mad to have to pass things by value...
In that case passing by value seems like the way to go. Allocating a new BankRecord pointer will work too. Storing things by reference is not very great.
However if I'm not mistaking, your two strings and the int won't be lost since they are present in the stack and will not be deallocated. But bankRecord will still be lost.
The best way to answer these concerns is to step through the code in the debugger and see what the Vector is doing with the variable being appended. Look especially at the constructor calls as you step into the data structure's Append functions. Because I do not know your underlying data structure, it is a bit more difficult for me to tell you more information. I will assume it is a std::vector for now until told otherwise.
You may be surprised to learn that references passed through a function do not tell the entire story about when it will go in and out of scope. I often think of C++ references as pointers that do not need nullptr checks.
Your code will work fine as long as the reference is copied into the vector or does not go out of scope because the variable it pointed to was destroyed. The reference will not go out of scope if it is referring to a member variable or memory on the heap for your particular case.
If the reference was declared on the stack to a variable created on the stack, and then appended to the vector, then you will have scope problems.
You should also look into emplace() if you have C++11 and the compiler supports move semantics.
In short, the most important thing you can do here is step through the code and see what Constructors are being called. This will give you the answer you desire.

Can the address of an object change?

I would like to use a std::map (or prob. std::unordered_map) where i insert custom object keys and double values, e.g. std::map<CustomClass,double>.
The order of the objects does not matter, just the (fast) lookup is important. My idea is to insert the address/pointer of the object instead as that has already have a comparator defined, i.e. std::map<CustomClass*,double>
In
Pointers as keys in map C++ STL
it has been answered that this can be done but i am still a bit worried that there might be side effects that are hard to catch later.
Specifically:
Can the address of an object change during runtime of the program? And could this lead to undefined behavior for my lookup in the map?
A test program could be:
auto a = adlib::SymPrimitive();
auto b = adlib::SymPrimitive();
auto c = adlib::mul(a,b);
auto d = adlib::add(c,a);
// adlib::Assignment holds std::map which assigns values to a,b
auto assignment = adlib::Assignment({&a,&b},{4,2});
// a=4, b=2 -> c=8 -> d=12
adlib::assertEqual(d.eval_fcn(assignment), 12);
which is user code, so users could potentially put the variables into a vector etc.
Update:
The answers let me think about users potentially inserting SymPrimitives into a vector, a simple scenario would be:
std::vector<adlib::SymPrimitive> syms{a,b};
auto assignment = adlib::Assignment({&syms[0],&syms[1]},{4,2}); // not allowed
The pitfall here is that syms[0] is a copy of a and has a different address. To be aware of that i could probably make the responsibility of the user.
Can the address of an object change during runtime of the program?
No. The address of an object never changes.
However, an object can stop existing at the address where it was created when the lifetime of the object ends.
Example:
std::map<CustomClass*,double> map;
{
CustomClass o;
map.emplace(&o, 3.14);
}
// the pointer within the map is now dangling; the pointed object does not exist
Also note that some operations on come containers cause the elements of the container to occupy a new object, and the old ones are destroyed. After such operation, references (in general sense; this includes pointers and iterators) to those elements are invalid and the behaviour of attempting to access through those references is undefined.
Objects never change address during their lifetime. If all you want to do is look up some value associated with an object whose address is known at the time of the lookup, then using the address of the object as the key in a map should be perfectly safe.
(It is even safe if the object has been destroyed and/or deallocated, as long as you don't dereference the pointer and only use it as a key for looking up an item in the map. But you might want to figure out how to remove entries from the map when objects are destroyed or for other reasons shouldn't be in the map any more...)

Adding function parameters to a vector

Coming from a Java background I am confused with how C++ allows passing objects by value. I have a conceptual doubt regarding when objects are passed by value:
void add_to_vector(vector<SomeClass>& v, SomeClass var) {
v.push_back(var);
}
Is this conceptually correct? Here is why I feel this is wrong: var is being passed by value and the memory for the object will be allocated on the stack for the function call. It is then getting added to the vector. At the end of the function call, the stack will be cleared and hence the object being referenced by var will also be cleared. So vector will now contain an object which no longer exists after the function call.
Am I missing something?
You are missing the powerful concept of value semantics. Just like var is a local copy in the function, std::vector is designed such that after v.push_back(var);, v holds a copy of var. This means that the elements of v can be used without having to worry where they came from (unless SomeClass has members with referential semantics, or in some way or another touches shared state.)
Yes, you're missing C++ value semantics. In Java, vectors only hold object references, object values themselves reside on the heap and are collected when no longer used. In C++, vectors hold object values, so practically always the vector will hold its own private value independent of function's local. Even if you passed var by reference, vector would hold its own private copy. Regard them as deep copies.
You might want to push_back(std::move(var)) here BTW, when var is passed by value in your example, if you don't plan to use the value after push_back.

Assigning pointer to an index in an array of pointers

I have a C++ class where I have a dynamically-allocated array of pointers to structs. I have a member function to "add an item" to this array by assigning an index of the array to the pointer to a dynamically allocated instance of the struct.
I have sort_arr initialized with sort_arr = new node *[this->max_items];.
In my assignment function I have sort_arr[this->num_items] = item; where the pointer is being passed as an argument with node *item.
In this function, I am able to access a member variable using (*sort_arr[i]).key_a (where i is the index), but once another item is added, this reference is no longer valid and causes a seg fault.
Is the pointer being deallocated, and if so, is it possible to prevent this?
EDIT: Sorry for the ambiguity here. I am trying to understand the problem generally and not specifically (in a pedagogical sort of way). I was hoping it was a problem with my conceptual approach. Given that it probably isn't, here are some more details:
node is defined as node **sort_arr; in the class declaration and then initialized by the constructor as sort_arr = new node *[this->max_items];. The insert method of the class executes: sort_arr[this->num_items] = item;, where item is passed with node *item.
It seems that after an item 'n2' is inserted after 'n1', 'n1' is no longer accessible via the reference (*sort_arr[num_items]).key_a. key_a is a member variable of the node struct.
EDIT 2: node *item is dynamically allocated outside of the class (in the main function).
The code you posted looks basically correct (if not the best way to do this sort of thing), but I can't tell what key_a is, or what context you are calling it in. Because of that, it's hard to tell exactly what the problem is. Posting the entire body of your function might be useful.
The only way something you allocated via new will be deallocated is if you (or some code you call) explicitly calls delete. That's pretty much the whole point of dynamic memory allocation, to allow your objects to live after the stack frame gets popped off.
My best guess with the current information is that you're trying to access a local value that got allocated on the stack after returning from the function. For example, this would cause a problem:
some_type* some_function(int i)
{
// ...
some_type p = (*sort_arr[i]).key_a; // p is a copy of key_a, allocated on the stack
// ...
some_type* result = &p;
return result;
}
In this scenario, p would be okay to return directly (if you changed the return type to some_type instead of some_type*), but you can't return a pointer to a local value. The local value is no longer valid after the function exits. This often causes a segfault.
Make sure that this->num_items as well asi is less than this->max_items and greater than -1, as this could be the cause of seg-fault.
Don't use dynamic arrays if it isn't for lecturing. Use a simple and save std::vector. It handles nearly everything that could go wrong. Try with that and see if there's still a seg-fault.
As noted, the code does appear to be correct. The problem was unrelated to the referenced code. I had been debugging some memory leaks and was deleting the referenced items, which was in turn causing the problem (quite obviously now that I see that).
I appreciate everyone's help and I'm sorry if I drove anyone crazy trying to find what was wrong.