/* Lecture code 7.0
 *
 * Exception-safe linked-list generation code.
 *
 */

#include <iostream>
#include <string>
#include <stdexcept>
#include <cstdlib>
#include <memory> // for auto_ptr
using namespace std;

struct nodeT
{
	int data;
	nodeT *next;
};

string GetLine()
{
	string result;
	getline(cin, result);
	return result;
}

/* Has a 50% chance to throw an exception.  Otherwise returns a random number
 * between 0 and 9, inclusive.
 */
int ComplexFunction()
{
	if(rand() % 2 == 0)
	{
		runtime_error error("Bad luck!");
		throw error;
	}
	return rand() % 10;
}

/* An exception-safe version of GetNewNode that uses an auto_ptr to manage the dynamically-
 * allocated memory.  Note that the return value is also an auto_ptr, so the calling function
 * can discard the return value without leaking memory.
 */
auto_ptr<nodeT> GetNewNode()
{
	auto_ptr<nodeT> node(new nodeT);
	node->next = NULL;
	node->data = ComplexFunction();
	return node;
}

void PrintList(nodeT *list)
{
	cout << "List contains: ";
	while(list != NULL)
	{
		cout << list->data;
		if(list->next != NULL)
			cout << " -> ";
		list = list->next;
	}
	cout << endl;
}

int main()
{
	nodeT *linkedList = NULL;
	while(true)
	{
		cout << "Type 'q' to quit: ";
		if(GetLine() == "q")
			break;

		try
		{
			/* Since GetNewNode returns an auto_ptr, we need to call release() to
			* have the auto_ptr stop managing the resource.
			*/
			nodeT *newNode = GetNewNode().release();
			newNode->next = linkedList;
			linkedList = newNode;
	
			PrintList(linkedList);
		}
		/* Catch runtime_error objects.  The "catch-by-reference" is for efficiency
		 * and otherwise is identical to catch(runtime_error error)
		 */
		catch(runtime_error &error)
		{
			cout << error.what() << endl;
		}
	}

	while(linkedList != NULL)
	{
		nodeT *next = linkedList->next;
		delete linkedList;
		linkedList = next;
	}

	return 0;
}