Doubly-linked lists using references rather than pointers (C++)

Started by
14 comments, last by SiCrane 15 years, 4 months ago
Just a thought; how would I implement a doubly-linked list where each node stores its previous and next nodes by reference? Since the references must be set in the node constructor, there is a two-way dependency between one node and the next, so the list's creator would need to construct all nodes simultaneously! I guess I'm barking up the wrong tree and that you nice people will tell me to use pointers or smart pointers instead, but I shall ask anyway, just in case everything I know is wrong :)
Advertisement
Considering references can't be reassigned, this doesn't seem like a great idea.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
You couldn't implement a terminal value either - because a reference has to be valid.
Here you go..

template <class T>struct Reference {  T &value  Reference(T &v) : value(v) {}};template <class T>struct LinkedListNode {  Reference<T> *left;  Reference<T> *right;  LinkedListNode() : left(NULL), right(NULL) {}  void setLeft(T &v) {    delete left;    left = new Reference<T>(v);  }  void setRight(T &v) {    delete right;    right = new Reference<T>(v);  } };


Yes, this is a silly post.
Quote:Original post by rip-off
You couldn't implement a terminal value either - because a reference has to be valid.
Use a polymorphic node type [smile]

Quote:Original post by ToohrVyk
Quote:Original post by rip-off
You couldn't implement a terminal value either - because a reference has to be valid.
Use a polymorphic node type [smile]


Or a singleton....

struct Node {	explicit Node(const Node & n) : next_(n) {}	static const Node & null_node() {		static Node instance;		return instance;	}	bool has_next()     const { return !(next_ == null_node().next_); }	const Node & next() const { return next_; }private:	friend bool operator==(const Node & lhs, const Node & rhs);	Node() : next_(null_node()) {}	const Node & next_;};bool operator==(const Node & lhs, const Node & rhs) {	return (&lhs.next_ == &rhs.next_);}int count(const Node & n) {	return n.has_next() ? (count(n.next()) + 1) : 1;}int main(int argv, char **){		Node a(Node::null_node());	Node b(a);	Node c(b);	Node d(c);	std::cout << count(d) << std::endl;}
Quote:Original post by hymerman
how would I implement a doubly-linked list where each node stores its previous and next nodes by reference?

Storing things by reference is very seldomly a good idea. You aren't meant to hold on to references. Use pointers.

References were introduced into the language to support operator overloading for user-defined types better, so you could write expressions like b + c instead of *b + *c.
Arg... that looks dangerously close to undefined behaviour Antheus. It seems like you are using a reference before it is initialised, because we are still in the process of initialising it.

I am probably wrong though.
struct Node {	explicit Node(const Node & n) : next_(n) {}	static const Node & null_node() {		static Node instance;		if(!finished)		{			std::cout << "returning a reference to an uninitialised value\n";		}		return instance; 	}	bool has_next()     const { return !(next_ == null_node().next_); }	const Node & next() const { return next_; }private:	friend bool operator==(const Node & lhs, const Node & rhs);	Node() : next_(null_node())	{		finished = true;	}	const Node & next_;	static bool finished;};bool Node::finished = false;bool operator==(const Node & lhs, const Node & rhs) {	return (&lhs.next_ == &rhs.next_);}int count(const Node & n) {	return n.has_next() ? (count(n.next()) + 1) : 1;}int main(int argv, char **){		Node a(Node::null_node());	Node b(a);	Node c(b);	Node d(c);	std::cout << count(d) << std::endl;}

But I will concede that it is a beautiful method, undefined behaviour or not!
Fair enough, I figured that was probably the case! I'll stick to pointers in this case.

Quote:Original post by DevFred
Storing things by reference is very seldomly a good idea. You aren't meant to hold on to references. Use pointers.


Why is that, exactly? Holding on to either is dangerous in exactly the same way (can point to invalid object), what makes references worse? I prefer references since they can't be NULL and are guaranteed to be initialised.
I would guess it depends. If the code guarantees that the reference stays valid for the lifetime of the object it might be OK (e.g a member of a class has a reference to the instance that contains it).

Be warned, though, that through programmer errors it is perfectly possible to obtain invalid and uninitialized references.

int& a = a; 

This topic is closed to new replies.

Advertisement