Search code examples
c++pointersmemorynew-operator

What is the difference between using `new classObject` and `&classObject` when creating a new object?


Below is my code, in which I defined two classes Node and List that do what you think they do. While extending the list, I need to create a new Node object (see the line with comment in my code). If I use new Node(data) then everything seems fine and the output is

2 3 5

But if I change it to &Node(data), the output becomes

7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648
7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648 7530648

(and so on; doesn't end unless I close the window)

What is the difference between using new Node(data) and &Node(data) here? Why is the output of the second case so weird?

Note that I used the -fpermissive option for my TDM-GCC-64-5.1.0 compiler. While this seems like a bad choice, I just realized what I am actually unsure of is how long the Node object created by the expression Node(data) lives. So hopefully this question will still be useful to those who might have the same confusion.

#include<iostream>
using namespace std;

class Node
{
    int _data;
    Node* _next;
public:
    Node(int data) { _data = data; _next = 0; }
    void setNext(Node* next) { _next = next; }
    Node* getNext() const { return _next; }
    int getData() const { return _data; }
};

class List
{
    Node* _head;
public:
    List() { _head = 0; }
    void add(int data)
    {
        if(!_head)
        {
            _head = new Node(data);
            return;
        }
        Node* temp = _head;
        while(temp->getNext())
            temp = temp->getNext();
        temp->setNext(new Node(data)); // What if I use `&Node(data)` instead of `new Node(data)`?
    }
    void print() const
    {
        Node* temp = _head;
        while(temp)
        {
            cout<<temp->getData()<<" ";
            temp = temp->getNext();
        }
    }
};


int main()
{
    List L;
    L.add(2);
    L.add(3);
    L.add(5);
    L.print();
}

Solution

  • What is the difference between using new classObject and &classObject

    new classObject Creates a new object of type classObject with dynamic storage.

    &classObject returns the address of the object named by the identifier classObject.

    &Node(data)
    

    This expression is ill-formed. The operand of the addressof operator is an rvalue here. That is not allowed. A compiler is not required to succesfully compile the program, and the standard does not describe how the program should behave. Here is example output from a compiler chosen at random:

    error: taking the address of a temporary object of type 'Node' [-Waddress-of-temporary]
            temp->setNext(&Node(data));
                          ^~~~~~~~~~~
    

    Some compilers do allow this as a language extension however. In such case this creates a temporary object of type Node. The lifetime of the temporary lasts until the end of that full expression. The addressof operator is applied on the temporary and the result is a pointer to the temporary. After the full expression, the pointer value will be invalid.

    Attempting to access the temporary outside of its lifetime through the invalid pointer will have undefined behaviour.

    Why is the output of the second case so weird?

    Because the behaviour of the program is undefined.


    Node* _next;
    void setNext(const Node* next) { _next = next; }
    

    A pointer to const is not implicitly convertible to a pointer to non-const. This is also ill-formed. Here is example output from a compiler chosen at random:

    error: assigning to 'Node *' from incompatible type 'const Node *'
        void setNext(const Node* next) { _next = next; }
                                                 ^~~~