0

The code should result in segmentation fault due to shallow copy but instead it allows printing the address of the the head node for list2 when printAll() is called for list2 in main().What should be done to get the expected behaviour ?Also please explain why is it happening ? I am a beginner.Thanks in advance.

>>>> when tried with #pragma pack(1) it resuted in the first output

>>>> Without #pragma pack(1) it resulted in the second output



Here is the code i wrote.
The code is for creating an object (list1) of SLL class(singly linked list) and copying it to another object(list2) of SLL class.
#include <iostream>
using namespace std;

//#pragma pack(1)
class Node{
        public:
                char letter;
                Node *next;
};
class SLL{
        private:
                Node *head, *tail;
        public:
                SLL(){
                        head = NULL;
                        tail = NULL;
        }
        void printAll();// for printing the list
        void insertNewNode(char item);// for insertion at head                                
        //function for deletion at head
        void deleteAtHead(){ 
                   Node *tmp;
                   tmp = this->head;
                   this->head = this->head->next;
                   free(tmp);
        }
};
//it is for printing a singly linked list
void SLL::printAll(){

        Node *p;
        p = head;
        cout<<"VALUE  "<<"           "<<"  ADDRESS"<<endl;
        while(p!=NULL){
                cout <<p->letter << "--------------- "<<p<<endl;
                p = p->next;
        }
}
void SLL::insertNewNode(char item){
        Node* temp;
        temp = (Node *)malloc(sizeof(Node));
        temp->letter = item;
        temp->next = head;
        head = temp;
}
int main(){
        SLL list1;
        list1.insertNewNode('D');
        list1.insertNewNode('C');
        list1.insertNewNode('B');
        list1.insertNewNode('A');

        cout<<"PRINTING LIST1"<<endl;
        list1.printAll();
        cout<<""<<endl;

        cout<<"SHALLOW COPY INVOKED"<<endl;
        SLL list2 = list1;
        cout<<""<<endl;

        cout<<"PRINTING LIST2"<<endl;
        list2.printAll();

        list1.deleteAtHead();
        cout<<""<<endl;

        cout<<" LIST1 AFTER ITS HEAD DELETION"<<endl;
        list1.printAll();
        cout<<""<<endl;

        cout<<" LIST2"<<endl;
        list2.printAll();       // as soon as this is executed it should result in runtime error
        return 0;
}


>>>>>>> Output1:
PRINTING LIST1
VALUE               ADDRESS
 A ------------- 0x5578d6f872e0
 B ------------- 0x5578d6f872c0
 C ------------- 0x5578d6f872a0
 D ------------- 0x5578d6f87280

SHALLOW COPY INVOKED

PRINTING LIST2
VALUE               ADDRESS
 A ------------- 0x5578d6f872e0
 B ------------- 0x5578d6f872c0
 C ------------- 0x5578d6f872a0
 D ------------- 0x5578d6f87280

 LIST1 AFTER ITS HEAD DELETION
VALUE               ADDRESS 
 B  ------------- 0x5578d6f872c0
 C  ------------- 0x5578d6f872a0
 D  ------------- 0x5578d6f87280

 LIST2
VALUE               ADDRESS
  --------------- 0x5578d6f872e0

>>>>>> Output2:

PRINTING LIST1
VALUE               ADDRESS
 A ------------- 0x55baac1032e0
 B ------------- 0x55baac1032c0
 C ------------- 0x55baac1032a0
 D ------------- 0x55baac103280

SHALLOW COPY INVOKED

PRINTING LIST2
VALUE               ADDRESS
 A  ------------- 0x55baac1032e0
 B  ------------- 0x55baac1032c0
 C  ------------- 0x55baac1032a0
 D  ------------- 0x55baac103280

 LIST1 AFTER ITS HEAD DELETION
VALUE               ADDRESS
 B  ------------- 0x55baac1032c0
 C  ------------- 0x55baac1032a0
 D  ------------- 0x55baac103280

 LIST2
VALUE               ADDRESS
--------------- 0x55baac1032e0
B--------------- 0x55baac1032c0
C--------------- 0x55baac1032a0
D--------------- 0x55baac103280
  • C++14 has smart pointers. Use them. It also has built-in lists. Use them also. – EvertW Oct 11 '19 at 13:15
  • @EvertW as a part of the learning process i m trying to explore as much as i can therefore i tried it – prabh coder Oct 11 '19 at 13:19
  • you are teaching yourself to re-invent the wheel. You should try to make a program that is useful / fun to you, using the language as good as possible. smartpointers and lists, hashmaps etc, as found in the Standard Template Library, make low-level memory management obsolete. You should (almost) never use new, delete and pointer arithmetic directly, in modern C++. – EvertW Oct 11 '19 at 13:25
  • @EvertW In C++ one is constantly confronted with low-level implementation details. Without understanding how pointers work (to the degree required to write a proper linked list), you won't get anywhere. Please don't discourage people from learning the dirty basics. – Max Langhof Oct 11 '19 at 13:38
  • That said, don't use `malloc` and `free` in C++ (caveats apply), they do not call the proper constructors and destructors. Use `new` and `delete` while learning, and use smart pointers when writing "real world code". – Max Langhof Oct 11 '19 at 13:41
  • Possible duplicate of [C++ delete - It deletes my objects but I can still access the data?](https://stackoverflow.com/questions/1930459/c-delete-it-deletes-my-objects-but-i-can-still-access-the-data) (and half of the ones linked in the sidebar there). – Max Langhof Oct 11 '19 at 13:43
  • @MaxLanghof: I strongly disagree here. C++ has had a major overhaul in 2012, that made the old, C-like approach to memory management (largely) obsolete. New programmers should learn to program in the new way, as the old ways will teach them bad habits, which are also the main cause of bugs in C++ programs. C++12 feels like a new language (stroustrup), and should be learnt like one. – EvertW Oct 11 '19 at 13:55
  • @EvertW I solely agree to the point that you are making. But this code has contrasted all the learning i had till now . So please could you just help me understand how this undefined behaviour is occuring.Please help(I really want to know). – prabh coder Oct 11 '19 at 14:09
  • @EvertW You still need to fully understand resource ownership to use smart pointers (or move semantics) correctly. The simplest way to get there is to learn manual memory management, see how awful it is, then move on to smart pointers. But I'll step out of this discussion, this is not the place. – Max Langhof Oct 11 '19 at 14:15
  • @MaxLanghof: from a educational point of view, it is better to teach methods that get the fastest progress and the more solid programming styles. This is the approach used by e.g. Koenig and Moo in "Accelerated C++", and Meyers in "Effective C++". Mucking about with low-level pointers is bad style in modern C++, and a cause of much pain, that can largely be avoided by the modern constructs. – EvertW Oct 11 '19 at 14:32
  • Sorry, C++ go its overhaul in 2011. 2012 was when C got its overhaul. I confused the two... – EvertW Oct 11 '19 at 14:36

1 Answers1

1

Pointers point into some region of memory. Any region of memory. Programs get their memory from the operating system, which usually gives it in large chunks ('Pages') that the program runtime then subdivides. The routines that are called by malloc, new and free, delete do this, but also the mechanisms to call and return from subroutines.

Trying to use a place in memory that has not been allocated to the program results in a Segmentation Fault. But using memory that was allocated to the program does not result in faults.

Programs do not usually give back pages that were allocated to them. Instead, the memory is just re-used, e.g. to store different variables. This is an optimisation, as it costs a lot of effort for the OS to allocate memory. It also reduces the amount of cache a program uses.

That is why the so-called 'dangling pointer' is so dangerous. When you use it, it returns data. Only close inspection will show that the data makes no sense. It may even return correct data for a long time, until the memory region is recycled and overwritten by something else. Then your program suddenly shows 'undefined behaviour'...

EvertW
  • 1,160
  • 9
  • 18
  • 1
    To be clear, it is undefined behavior from the start. It might not manifest itself in anything observable (i.e. it might keep doing "the right thing") until later, but it still is undefined behavior right away. But it might also manifest itself _before_ you even "reach" that code: https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633 – Max Langhof Oct 11 '19 at 14:27
  • @MaxLanghof: Aye, the miseries of this particular type of bug are many and painful. Only slightly better than race conditions... – EvertW Oct 11 '19 at 14:39