2
/*
 * Definition for linked list.
 * class Node {
 *  public:
 *      int data;
 *      Node *next;
 *      Node *child;
 *      Node() : data(0), next(nullptr), child(nullptr){};
 *      Node(int x) : data(x), next(nullptr), child(nullptr) {}
 *      Node(int x, Node *next, Node *child) : data(x), next(next), child(child) {}
 * };
 */

Node* merge(Node* &a, Node* &b){
    
    Node* temp = new Node(0);
    Node* ans = temp;
    
    while(a!=NULL && b!=NULL){
        
        if(a->data < b->data){
            ans->child = a;
            ans = a;
            ans->next = NULL;
            a = a->child;       
        }
        else{
            ans->child = b;
            ans = b;
            ans->next = NULL;
            b = b->child;
        }
    }

    while(a!=NULL){
        ans->child = a;
        ans = a;
        ans->next = NULL;
        a = a->child;
    }
    
    while(b!=NULL){
        ans->child = b;
        ans = b;
        ans->next = NULL;
        b = b->child;
    }
    
    temp = temp->child;
    ans->child = NULL;
    return temp;
}

Node* flattenLinkedList(Node* head) 
{
    // Write your code here
    if (head == NULL || head->next==NULL) {
        return head;
    }

    return merge(head, flattenLinkedList(head->next));
}
Compilation Failed
In file included from runner.c++:21:0:
solution.h: In function 'Node* flattenLinkedList(Node*)':
solution.h:61:38: error: invalid initialization of non-const reference of type 'Node*&' from an rvalue of type 'Node*'
  return merge(head, flattenLinkedList(head->next));
                                      ^
solution.h:14:7: note:   initializing argument 2 of 'Node* merge(Node*&, Node*&)'
 Node* merge(Node* &a, Node* &b){
       ^
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • I think [this](https://stackoverflow.com/a/8294009/2550406) answers your question. I found it by searching for your error `invalid initialization of non-const reference of type rvalue` – lucidbrot Jul 12 '23 at 08:16
  • I did not understand. – Jahnvi Agarwal Jul 12 '23 at 08:18
  • 2
    @JahnviAgarwal Do not tag `dsa`. Did you read what the `dsa` tag means? – PaulMcKenzie Jul 12 '23 at 08:20
  • if `merge` wants to modify its second parameter (ie its a non-const reference), then it does not make sense to pass it a temporary (the pointer returned from the `flattenLinkedList` function). – 463035818_is_not_an_ai Jul 12 '23 at 08:26
  • 1
    why does `merge` take two non-const references? Does merging two lists modify the heads of the two original lists? – 463035818_is_not_an_ai Jul 12 '23 at 08:28
  • Yes after merging head is modified – Jahnvi Agarwal Jul 12 '23 at 08:34
  • @JahnviAgarwal I've tried to explain (below in an answer) what I've read in the Q&A I've linked but tbh I am not sure at all about my interpretation. It's just my best guess. I hope somebody else can clarify it better. I have retracted my close vote because while the questions might have the same answer, your question actually also needs additional explanation for the specific case you are presenting here – lucidbrot Jul 12 '23 at 09:07
  • Your `merge` function leaks memory. Try implementing it without calling `new`. – n. m. could be an AI Jul 12 '23 at 09:22
  • Why do you need `merge` parameters to be references? After merging, both become null pointers. The caller doesn't get any new information from this. – n. m. could be an AI Jul 12 '23 at 09:27

1 Answers1

1

Since you said the linked Q&A was not enough, here's my attempt. I hope it's not wrong, but it sounds plausible to me:

Your function signatures

Node* flattenLinkedList(Node* head) 
Node* merge(Node* &a, Node* &b)

describe that flattenLinkedList returns a Node* - a pointer to a Node. And that merge takes a Node* by reference. The thing about taking a reference and using it is: the referenced object should still exist by the time you use it. In your case the referenced object is a pointer.

But because c++ is weird (in other words, I do not know enough to explain this) the scope of the argument is quite short-lived. Let's say you'd split it up, like they do in this question:

{
Node* temp = flattenLinkedList(head->next);
return merge(head, temp);
}

This conceptually does the same thing, except that temp has a clear scope: once you exit the function's {} block by returning, temp will no longer exist.

If you do it both in the same line though, as you have done

return merge(head, /* temp */ flattenLinkedList(head->next));

then the temp you return from flattenLinkedList might cease to exist immediately... This is the problem the compiler is pointing out (I think).

The linked question has a comment on this:

Note that there isn't a strict technical reason for this restriction. It would have been just as easy to implement to allow mutable references to temporaries. Forbidding it is a design decision of C++

Sidenote: what is the point of having a non-const reference as an argument if you discard temp anyway after it is modified? You could also make the second argument of merge a Node* b instead of a Node* &b, right?

lucidbrot
  • 5,378
  • 3
  • 39
  • 68