0

I am writing node and I"ve met a problem this is recognized as nullptr by if while it shouldn't be (At least that's what I think). And there is another problem when I use constructor with value this->next points to this.

I expect explenation or if I understend something wrong solution to my problem. I really don't know why this happens. Maybe I'm not understanding how this is working exacly.

#pragma once
#include"mstring.h"

template<typename T>
class node
{
private:
    T data;
    node* next;
    node* prev;
public:
    node();
    node(T _data);
    ~node();
    T& operator[](int index);
    int GetSize();
    void AddFront(T new_data);
    void AddBack(T new_data);
    void DeleteFront();
    void DeleteBack();

};

template<typename T>
node<T>::node() : prev(nullptr), next(nullptr) {};

template<typename T>
node<T>::node(T _data)
{
    data = _data;
    prev = nullptr;
    next = nullptr;
}

template<typename T>
void node<T>::AddFront(T new_data)
{
    node* temp_node = new node();
    temp_node->prev = nullptr;
    temp_node->data = new_data;
    temp_node->next = this;
    if (this != nullptr)
        (this)->prev = temp_node;
    *this = *temp_node;

}

template<typename T>
void node<T>::AddBack(T new_data)
{
    node* temp_node = new node();
    temp_node->next = nullptr;
    temp_node->data = new_data;
    if (this == nullptr)
        temp_node->prev = nullptr;

    node* end_node = this;
    while (end_node->next != nullptr)
        end_node = end_node->next;

    end_node->next = temp_node;
    temp_node->prev = end_node;
}
#include"node.h"

int main()
{
    node<int> numbers(2);
    numbers.AddFront(1);
    numbers.AddBack(3);
    for (int i = 0; i < numbers.GetSize(); i++)
        std::cout << numbers[i] << ' ';

}
Binio
  • 23
  • 3
  • 18
    If `this` is ever `nullptr`, you are in some serious trouble. – Yksisarvinen Mar 21 '23 at 22:32
  • Yep. If you're in a non-`static` class member function without a valid instance, the program's already broken. – user4581301 Mar 21 '23 at 22:33
  • 1
    Yes, really. Think about it. If `this` is `nullptr`, on which object are you calling the function then? – Thomas Weller Mar 21 '23 at 22:33
  • Why would a node, something that should be a single piece of a list or graph, have an index operator? Showing the implementation of `operator[]` might help answer that question. – user4581301 Mar 21 '23 at 22:37
  • 2
    Mind you on reading further, it looks like you've conflated the node with the container of nodes. nodes should be really stupid, knowing barely enough to hold data and point a user at the surrounding items in the graph. Some other structure should represent the graph. In this case you probably want a `DoublyLinkedList` class that contains and manages the `node`s. Having a node be both node and container places too much responsibility on one object and will lead to mistakes. – user4581301 Mar 21 '23 at 22:39
  • Side note: An index operator in a linked list or graph usually doesn't make much sense. An index operator is typically used when you can directly access any of the items in the container at any time. With a list or graph you have to keep getting the next item in the chain and keep count to know when you've found the node that would be at the desired index. Typically this hides a huge performance penalty from the class's users and they write crappy code as a result. – user4581301 Mar 21 '23 at 22:44
  • 1
    The `this` pointer **cannot** be `nullptr` for any **valid** program. – Eljay Mar 21 '23 at 23:00
  • *"At least that's what I think"* -- What led you to this conclusion? Don't make us rely on a conclusion drawn by someone who does not understand what is going on. Give us hard observations. Adjust your [mre] to show symptoms, even if (especially if) it means no longer trying to demonstrate a linked list. – JaMiT Mar 22 '23 at 01:14
  • The C++ standard guarantees that `this` is never `nullptr` (for well defined, correct programs), so checking that is never required. It would be [UB](https://en.cppreference.com/w/cpp/language/ub) if `this` was ever `nullptr`. – Jesper Juhl Mar 22 '23 at 02:08

1 Answers1

4

this can never be null.

I'm guessing you're coming from a C background, where it could make sense to do something like this:

void NodeAddBack(node** this, int value) {
    node* newNode = NodeNew(value);
    if (*this == NULL) {
        *this = newNode;
    } else {
        (*this)->next = newNode;
    }
}

int main() {
    node* list = NULL;
    NodeAddBack(&list, 42);
}

You may think that translates fairly directly to something like this in C++:

template <typename T>
void node<T>::AddBack(T value) {
    node<T>* newNode = new node<T>(value);
    if (this == nullptr) {
        this = newNode;
    } else {
        this->next = newNode;
    }
}

int main() {
    node<int>* list = nullptr;
    list->AddBack(42);
}

But that second snippet is totally invalid. You are not allowed to call a non-static member function via a null pointer, nor are you allowed to assign to this. In any well-formed program, this is always non-null and points to the object on which the currently-executing member function was called.

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
  • 3
    As a side note, if you write code that tests the `this`-pointer to see if it's NULL and then does something different based on the result, don't expect it to behave the way you'd like -- in particular, the compiler and optimizer can and will assume `this` is always non-NULL and implicitly strip the `if (this == NULL) {/* do something*/}` code right out of the executable, because it "knows" that test can never be true :) – Jeremy Friesner Mar 22 '23 at 00:45