Is __builtin_prefetch safe to be call with nullptr - c++

Suppose we have linked list and code like this:
void play_with_list(struct int_list *list) {
while (list != NULL) {
__builtin_prefetch(list->next);
do_something(list->n);
list = list->next;
}
}
On the last iteration, __builtin_prefetch will be called with nullptr, because list->next is nullptr.
Is that safe?
Second part of the question - suppose list data is pointer to C string (char *) allocated on the heap. Will it be beneficial if I prefetch it too?

Related

Deleting nodes recursively

I have created this function to recursively delete nodes from a doubly linked list. The issue here is that based on the call stack, it starts from the second so it does not delete the entire list. I can delete the remaining node from the method where I'm calling this but there should be a way around that. Is there a way of resolving this issue?
void RecursiveClear(const Node* _curr) {
if(_curr != nullptr) {
//_curr->prev = _curr;
_curr = _curr->next;
RecursiveClear(_curr);
}
if (_curr != nullptr) {
delete _curr;
}
}
First: Don't use a leading _.
You modify _curr in the function so by the time you end up at the delete the original pointer is gone. So don't do that, just call the function wiht the next value without modifying the local vbariable:
RecursiveClear(_curr->next);
You also shouldn't do a recursion like that because lists can be long. Your code is not tail recursive. Every node in the list will use up a little bit of stack space. For long lists this will overflow the stack and crash.
Use a temporary so you can reorder the operations to be tail recursive:
void RecursiveClear(const Node* curr) {
if (curr != nullptr) {
const Node *next = curr->next;
delete curr;
RecursiveClear(next);
}
}

Doubly linked list C++ Delete element

I have problem with deleting first and last element of linked list. When I am trying to delete first element, my code do nothing (when I print a list, deleted element is still there). When I am trying to delete the last one, console shows core dumped.
Here is my code:
void Delete_element(point del, node *elem) {
struct node *temp = elem;
if(elem->p.x==del.x && elem->p.y == del.y) {
elem=elem->next;
return;
} else {
while(elem->next->next!=NULL) {
if(elem->next->p.x==del.x && elem->next->p.y==del.y) {
temp=elem->next;
elem->next=elem->next->next;
elem->prev=temp->prev;
return;
}
temp=temp->next;
}
}
if(elem->next->p.x==del.x && elem->next->p.y==del.y) {
elem->next=NULL;
}
}
EDIT: After fixes
void Delete_element(point del, node *& elem){
struct node *temp = elem;
if(elem->p.x==del.x && elem->p.y == del.y){
temp = elem->next;
free(elem);
elem=temp;
return;
}else{
while(elem->next->next!=NULL)
{
if(elem->next->p.x==del.x && elem->next->p.y==del.y)
{
temp=elem->next;
elem->next=elem->next->next;
elem->next->prev=elem;
return;
}
elem=elem->next;
}}
if(elem->next->p.x==del.x && elem->next->p.y==del.y){
elem->next=NULL;
return;
}
}
Now removing an middle element is broken.
Please help
Firstly, you are not actually deleting anything. You are, however, leaving dangling pointers which result in a memory leak. In each case you should be deleting something. This is why you still see the data instead of garbage or some kind of crash.
Second, you look to have an infinite loop. When you hit your while loop you never change elem so elem->next->next never changes.
Third, why are you deleting elem->next in your while loop? Delete elem to avoid confusion.
EDIT:
You can't change elem like that. Think of elem like an integer or float you pass in. If you want elem to maintain the head change you're going to have to pass in a pointer to elem which ends up being a pointer to a pointer.
I believe you have at least two bugs:
In order to modify the first element you must pass a reference to the first pointer as you intent to modify this pointer. use:
void Delete_element(point del, node *& elem)
Removing an element from the middle seems to be broken.
instead of:
elem->prev=temp->prev
you should have:
elem->next->prev=element

Removing last element in LinkedList (C++)

I am writing a function to delete the last node in a linked list. This is what I have, and other code I've found online searching for a solution is very similar (I have found several), but when I execute it it creates some sort of infinite loop when deleting the last element of a linked list (it deletes other elements just fine though).
Here is the code I imagine is causing a problem:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
I imagine it's an issue with the memory (particularly after the delete head; statement), but I'm really stuck and would appreciate any help or an explanation for why this doesn't work (I possibly don't have a very good understanding of pointers and memory in C++, I'm just starting with it)
Here is my Node code for reference:
struct Node {
int key;
Node* next;
};
Thanks for any help!
Original code:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
The "other code" is not specified, but if the list has exactly one node then the above code will
delete that first node, and
update the local pointer head, which doesn't update the actual argument since it was passed by value.
As a result the calling code will be left with a dangling pointer in this case, a pointer pointing to a destroyed object, or to where such an object once was. Any use of such a pointer is Undefined Behavior. It might appear to work, or crash, or just silently cause dirty words tattoo to appear on your forehead – anything…
One fix is to pass the first-pointer by reference:
void delete_final(Node*& head){
if(head == nullptr) {
return; }
if(head->next == nullptr) {
delete head;
head = nullptr;
return;
}
//other code
}
A nice helper function for dealing with linked lists, is unlink:
auto unlink( Node*& p )
-> Node*
{
Node* const result = p;
p = p->next;
return result;
}
The implementation is perhaps a bit subtle, but all you need to remember to use it is that it updates the pointer you pass as argument, which should be either a first-node pointer or a next pointer in the list, and returns a pointer to the unlinked node.
So e.g. you can do
delete unlink( p_first );

How to implement erase method in a doubly linked list

I have to write a doubly linked list, I am trying to implement the erase(Type obj) method which takes an argument obj and traverses through the list and deletes every node which has the element obj.
The problem I am facing is, I am iterating through the linked list from front and when I find the node which has the obj element, I change the next/previous pointers of the the nodes before and after the node with obj element. However I am not DELETING the node with obj itself, as far as I know c++ has no garbage collection so the node which had obj is still somewhere hanging in the air. How do I delete that?
My erase()
template <typename Type>
int Double_list<Type>::erase( Type const &obj ) {
if (empty()){
return 0;
}
if (size() == 1 && head()->retrieve() == obj){
list_head = nullptr;
list_tail = nullptr;
list_size--;
return 1;
}
//Counter to hold the number of items deleted
int count = 0;
//Iterating through the linked list
for (Double_node<Type> *ptr = head(); ptr != nullptr; ptr = ptr->next()){
if (ptr->retrieve() == obj){
ptr->previous_node->next_node = ptr->next();
ptr->next()->previous_node = ptr->previous();
count++;
// delete ptr; // This stops me from iterating through the for loop
list_size--;
}
}
return count;
}
While you traversing your list, you are doing it using pointer to nodes which is of type Double_node<Type> *, which means that it was allocated somewhere and could be deleted with simple delete ptr, but since you are using it also to get next element in list you have to be careful and remember it prematurely, so it should be something like:
Double_node<Type> *ptr_next = 0;
for (Double_node<Type> *ptr = head(); ptr != nullptr; ptr = ptr_next) {
ptr_next = ptr->next ();
if (ptr->retrieve() == obj){
if (ptr->previous_node)
ptr->previous_node->next_node = ptr->next();
ptr->next()->previous_node = ptr->previous();
count++;
list_size--;
delete ptr;
}
I believe that should do the trick.
There is a syntax when deleting pointers and objects called delete.
example code:
obj *temp = getCurrentNode();
//set pointers in nodes to the correct places
delete temp; //This releases all of the memory used in the object back to the OS
temp = NULL;//good practice to set this to null, since it points to non-allocated memory
//but exiting the function will make the pointer 'temp' useless, anyway.

Question about linked lists/pointers in c++

The nature of pointers being NULL in C++ seems to feel arbitrary. I'm sure there's a method to it that I'm missing, but the following makes sense to me, but doesn't seem to work. I have the following method for adding a node to a linked list:
LLNode *ll; // set to NULL in constructor.
void addToLL(Elem *e)
{
LLNode *current = ll;
while(true)
{
// edge case of an empty list.
if (ll == NULL)
{
ll = new LLNode(e);
break;
}
else if (current == NULL)
{
current = new LLNode(e);
break;
}
else {
current = current->next;
}
}
}
When adding a 2nd node to the list, the case for current == NULL does not get caught, so it tries to call current = current->next and crashes do to accessing invalid memory. Why would this be the case? A LLNode has a pointer to an Elem, and a pointer called next to another LLNode.
You probably didn't set the next pointer to NULL in the LLNode constructor.
Objects of the basic types in C++ (pointer types, numeric types, etc.) have indeterminate initial values: they don't get initialized by default. You need to explicitly initialize such objects before you use them.
For this sort of thing you need a pointer to a pointer in order to strip away a lot of the needless exceptions in your implementation:
LLNode *ll = NULL;
void addToLL(Elem *e)
{
LLNode** current = &ll;
// While the current pointer to pointer is mapped to something,
// step through the linked list.
while (*current)
current = &(*current->next);
// At this point current is pointing to a NULL pointer and can
// be assigned to.
*current = new LLNode(e);
}
The reason pointers are NULL is because that evaluates to false and allows you to do simple checks such as while (*current) without a lot of overhead. In the CPU this usually ends up being implemented as a test-if-zero operation.
Pointers are only NULL if initialized as such. In C they are often undefined unless properly initialized and referencing an uninitialized pointer is recipe for disaster. You'll want to ensure any pointers you define are always initialized to something valid before using them.
1) You say that ll is set to NULL in the constructor. But what constructor? There's no class definition here. Is ll a global variable? And are you sure that the constructor for LLNode sets the next pointer to NULL?
2) The condition
if (ll == NULL)
can and should be checked outside of the loop, as ll is not modified inside the loop.
3) current is a local stack variable, so assigning to it will have no effect once the function exits. In particular, current = new LLNode(e) is a memory leak.
4) To add a node to the linked list, you must find the last node of the existing list, and modify its next pointer. Something like this would work:
// ll is a field representing the first node in your existing linked list.
if (ll == NULL) {
ll = new LLNode(e);
}
else {
current = ll;
while (current->next != NULL) {
current = current->next;
}
current->next = new LLNode(e);
}
EDIT: Modified the above based on your comment that ll is a class member.
The first thing I see in your code is that current is local, gets allocated with new but is never actually attached to the list.
Surely your code should be
else if( current->next == NULL )
{
current->next = new LLNode( e );
break;
}
LLNode must of course initialise next to NULL in its constructor.
Of course your list has O(N) insertion time, and if this is anything other than an exercise you should be almost certainly be using standard library containers.
You should also probably move the edge case out of the loop.