Is this function that returns by reference safe?

Hello. I never really learned how to return by reference in C++
but I was making a linked list class and I want to make a function:
T& operator[int index] and I'd guess I need to return a reference
to the node with the given index. So, is this code a safe way to do
that?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
T& operator[](int index)
{
    Node<T>* temp = head;
    int i = 0;
    
    while(temp != nullptr)
    {
        if(i == index)
            return temp;
        
        temp = temp->next;
        i++;
    }
}


I would guess it not to be safe since 'temp' goes out
of scope... Correct?

EDIT: Will this code cause undefined behavior?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <string>

template<typename T>
class Node
{
public:
    T data;
    Node* next;
};

template<typename T>
class List
{
public:
    ~List()
    {
        Node<T>* current = head;
        while (current != 0) {
            Node<T>* next = current->next;
            delete current;
            current = next;
        }
        head = 0;
    }

    List() noexcept = default;

    void Add(T value)
    {
        Node<T>* newNode = new Node<T>{ value, nullptr };

        if (head == nullptr) head = newNode;

        else
        {
            Node<T>* temp = head;

            while (temp->next != nullptr) temp = temp->next;

            temp->next = newNode;
        }
    }

    T& operator[](int index)
    {
        Node<T>* temp = head;
        int i = 0;

        while (temp != nullptr)
        {
            if (i == index)
                return temp->data;

            temp = temp->next;
            i++;
        }
    }

    int Count()
    {
        int _count = 0;

        Node<T>* temp = head;
        while (temp != nullptr)
        {
            _count++;
            temp = temp->next;
        }
        return _count;
    }

    void Display() const noexcept
    {
        Node<T>* temp = head;
        while (temp != nullptr)
        {
            std::cout << temp->data;
            std::cout << ' ';
            temp = temp->next;
        }
        std::cout << '\n';
    }
private:
    Node<T>* head = nullptr;
};

int main()
{
    List<std::string> list;
    list.Add("A");
    list.Add("B");
    list.Add("C");
    list.Display();
    std::cout << list.Count();
    std::cout << list[0]; // This is the line I think might cause problems.
    return 0;
}
Last edited on
This also makes it unsafe.
1
2
 In member function 'T& List<T>::operator[](int) [with T = std::basic_string<char>]':
58:5: warning: control reaches end of non-void function [-Wreturn-type]


If the subscript isn't in range, then perhaps
https://www.cplusplus.com/reference/stdexcept/out_of_range/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    T& operator[](int index)
    {
        Node<T>* temp = head;
        int i = 0;

        while (temp != nullptr)
        {
            if (i == index)
                return temp->data;

            temp = temp->next;
            i++;
        }
        throw std::out_of_range("oops");
    }

The code can be somewhat simplified. Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <string>

template<typename T>
class Node
{
public:
	T data {};
	Node* next {};
};

template<typename T>
class List
{
public:
	~List() noexcept
	{
		while (head != nullptr) {
			const auto next {head->next};

			delete head;
			head = next;
		}
	}

	List() noexcept = default;

	void Add(T value)
	{
		const auto newNode {new Node<T> {value, nullptr}};

		if (head == nullptr)
			head = newNode;
		else
		{
			auto temp {head};

			for (; temp->next != nullptr; temp = temp->next);
			temp->next = newNode;		}
	}

	T& operator[](size_t index)
	{
		auto temp {head};

		for (size_t i {}; temp != nullptr; temp = temp->next, ++i)
			if (i == index)
				return temp->data;

		throw std::out_of_range("Bad index");
	}

	size_t Count() const noexcept
	{
		size_t _count {};

		for (auto temp = head; temp != nullptr; temp = temp->next, ++_count);

		return _count;
	}

	void Display() const noexcept
	{
		for (auto temp = head; temp != nullptr; temp = temp->next)
			std::cout << temp->data << ' ';

		std::cout << '\n';
	}

private:
	Node<T>* head {};
};

int main()
{
	List<std::string> list;

	list.Add("A");
	list.Add("B");
	list.Add("C");

	list.Display();

	std::cout << list.Count() << '\n';
	std::cout << list[0] << '\n';

	try {
		std::cout << list[4] << '\n';
	}
	catch (const std::out_of_range& ex) {
		std::cout << ex.what() << '\n';
	}
}



A B C
3
A
Bad index


Last edited on
Topic archived. No new replies allowed.