Returning Nulls in Templates
I'm having a very difficult time returning NULLS in my program which
started out as an exercise of Linked Lists based on Lippman, but has
evolved as I test out new skills and methods. I've templated it an then
I added some hooks for MYSQLb but I've run into trouble with returning
NULL values of zero's, especially with the operator[] which requires the
return value being a reference. Let me copy and past a copy of the
entire program, since it is complex for me, but likely to be run of the
mill for the advanced C++ programmers here.
This is the main header file which was originally broken into a header
and a .cpp file but has since been combined to make the templates happy
================================================================================
#ifndef LINKLIST_H
#define LINKLIST_H
#endif
#include<iostream>
namespace CHAINLIST{
template<class unk>
class NODE{
public:
NODE<unk>( unk value, NODE<unk> *item_to_link_to = 0);
inline unk value();
inline unk& value_ref();
inline void value(unk);
inline NODE<unk> * next();
inline NODE<unk>& next_ref();
inline void next(NODE<unk> *);
NODE<unk> * err_node;
unk err_value;
~NODE<unk>();
private:
unk _value;
NODE<unk> *_next;
};
template<class unk>
inline NODE<unk>::NODE(unk value, NODE<unk> *item): _value(value) {
if (!item){
//std::cout << "_value=> " << _value << std::endl;
_next = 0;
}
else{
//std::cout << "insert after _value=> " << _value << std::endl;
//_next = item->_next;
next(item->next());
item->next(this);
//inserts after on construction
}
};
template<class unk>
inline unk NODE<unk>::value(){
if(this)
return _value;
else{
return 0;
}
}
template<class unk>
inline unk& NODE<unk>::value_ref(){
if(this)
return _value;
else{
return err_value;
}
}
template<class unk>
inline void NODE<unk>::value(unk val){
_value = val;
}
template<class unk>
inline NODE<unk> * NODE<unk>::next(){
if(this != NULL) {
return _next;
}
else {
return 0;
}
}
template<class unk>
inline NODE<unk>& NODE<unk>::next_ref(){
if(this != NULL) {
return *_next;
}
else {
return 0;
}
}
template<class unk>
inline void NODE<unk>::next(NODE<unk> * nxt){
_next = nxt;
}
template<typename unk>
class LIST{
public:
LIST<unk>() : _at_front(0), _at_end(0), _size(0) {}
inline int size();
inline void insert(NODE<unk> *, unk);
inline void insert(unk);
inline void front(unk);
inline void up_size();
inline void down_size();
void display(std::ostream &os = std::cout);
void remove_front();
void remove_all();
void remove_item(unk);
void remove_item(NODE<unk> *);
NODE<unk> * find(unk);
NODE<unk> * find_all(unk, NODE<unk> * last = NULL );
void sort(LIST& m );// add a sort algorithm - shell sort
unk& operator[](int);
unk err = 0;
~LIST<unk>();
private:
NODE<unk> *_at_front;
NODE<unk> *_at_end;
int _size;
LIST<unk>(const LIST<unk>&);
LIST<unk>& operator=( const LIST<unk>&);
};
template<typename unk>
inline unk& LIST<unk>::operator[](const int i){
//std::cout << "Size of List is " << size() << std::endl;
if( i >= size()){
std::cerr << "Index larger that List" << std::endl;
return err;
}
NODE<unk> * cur = _at_front;
int place;
for(place = 0; place < size(); cur = cur->next(), ++place){
if (place == i){
unk &k = cur->value_ref();
unk &j = k;
std::cout << "j ==> " << j << " k==> " << k << std::endl;
std::cout << "refernce value ==> " << cur->value_ref() << std::endl;
return j;
}
}
std::cerr << "Errror - This shouldn't get through the list without finding the index" << std::endl;
return err;
}
template<typename unk>
inline int LIST<unk>::size(){return _size;}
template<typename unk>
inline LIST<unk>::~LIST<unk>(){remove_all();}
template<typename unk>
inline void LIST<unk>::insert(NODE<unk> *ptr, unk value){
std::cout << "insert: ptr =>" << ptr << " value =>" << value << std::endl;
//std::cout << "insert: ptr =>" << ptr << " value =>" << value << std::endl;
if(ptr == 0){
std::cout << "insert in FRONT: ptr =>" << ptr << " value =>" << value << std::endl;
front(value);
return;
}
if(ptr == _at_end){
_at_end = new NODE<unk>(value,ptr);
up_size();
return;
}
new NODE<unk>(value,ptr);
up_size();
}
template<class unk>
inline void LIST<unk>::insert(unk value){
if(_at_end == 0){
front(value);
return;
}
NODE<unk> * new_item = new NODE<unk>(value, _at_end);
_at_end = new_item;
up_size();
}
template<class unk>
inline void LIST<unk>::up_size(){ ++_size; }
template<class unk>
inline void LIST<unk>::down_size(){ --_size; }
template<class unk>
inline void LIST<unk>::front(unk value){
NODE<unk> *tmp;
up_size();
if(_at_front){
tmp = _at_front;
_at_front = new NODE<unk>(value);
_at_front->next(tmp);
return;
}
_at_end = _at_front = new NODE<unk>(value);
return;
}
template<class unk>
void LIST<unk>::display(std::ostream &os){
NODE<unk> * tmp = _at_front;
if (tmp == 0){
os << "No List" << std::endl;
return;
}
//unk i =0;
while(tmp != _at_end){
//std::cout << "Entering While Loop: "<< ++i << std::endl;
os << tmp->value() << ":";
tmp = tmp->next();
}
os << tmp->value() << std::endl;
}
template<class unk>
NODE<unk>::~NODE<unk>(){
//std::cout << "List Item Destroyed" << std::endl;
}
template<class unk>
void LIST<unk>::remove_front(){
if(_at_front == 0){
std::cout << "No List" << std::endl;
return;
}
NODE<unk> * tmp = _at_front;
down_size();
_at_front = tmp->next();
if(tmp->next() == NULL)
_at_end = 0; //need to clear _at_end as well once you delete the last node
delete tmp;
return;
}
template<class unk>
void LIST<unk>::remove_all(){
std::cout << "********CLEANING OUT LIST*********" << std::endl;
while(_at_front){
// std::cout << "***node to remove***\nNode==> " << _at_front << "\tValue==> " << _at_front->value() << std::endl;
remove_front();
// std::cout << "Done with remove_all\n";
}
}
template<class unk>
NODE<unk> * LIST<unk>::find(unk search){
NODE<unk> * index;
if(_at_front == NULL)
return NULL;
index = _at_front;
while(index){
if( search == index->value())
return index;
index= index->next();
}
return NULL;
}
template<class unk>
NODE<unk> * LIST<unk>::find_all(unk search, NODE<unk> * last){
//find_all returns a NULL when it reaches the end of a list and the search node is not found
//find_all starts a fresh search from the beginning of a list if a Null is sent as a node value
//except for the NULL node, it begins searching with the NEXT node after the one sent to it (for convience of while loops)
//
//syntax is find_all(int, LIST<unk> *);
//
//
if(last == NULL){
last = find(search);
return last;
}
last = last->next(); //search forward
if( last == NULL){
return last;//past the end
}
// std::cout << "Not NULL: Last ==>" << last << " last_value()==> "<< last->value() << " Search==>" << search << std::endl;
while( last->value() != search){
if (last == _at_end)
return last->next();
last = last->next();
}
return last;
//if(last == _at_end){
// std::cout << "found end node. last=> " << last << " value=>" << last->value() << "\n\n";
// std::cout << "last->next()==> " << last->next() << " which is the end and should be null\n";
// return ((last->value() == search) ? last : last->next());
// if(last->value() == search)
// return last;
//
// std::cout << last->next() << " which is the end and should be null\n";
// return last->next(); //which should be null
// }
//std::cout << "Last ==>" << last << "is not at end==> " << _at_end << " and last value=> " << last->value() << "\n\n";
// return last;
}
template<class unk>
void LIST<unk>::remove_item(unk search){
NODE<unk>* node = find(search);
remove_item(node);
}
template<class unk>
void LIST<unk>::remove_item(NODE<unk> * node){
if(node == NULL)
return;
NODE<unk> * prev, *current;
if( _at_front == node){
remove_front();
return;
}
//Walk from the beginning in order to popular prev
prev = _at_front;
current = prev->next();
while (current != NULL){
if(node == current){
prev->next(current->next());
if(current == _at_end)
_at_end=prev;
delete current;
down_size();
return;
}
prev = current;
current = current->next();
}
return;
}
template <class T>
void LIST<T>::sort ( LIST<T>& v )
{
const size_t n = v.size();
for (int gap = n/2; 0<gap; gap/=2){
//cout << " gap==> " << gap << " n ==> " << n << endl;
for (int i = gap;i < int(n);i++){
//cout << "i ==> " << i << " gap==> " << gap << " n ==> " << n << endl;
for (int j=i-gap;0<=j ;j-=gap ){
//cout << "COMPARE::i ==> " << i << " j==> " << j << " gap==> " << gap << " n ==> " << n << endl;
//cout << "***Comparing " << j+gap << " and " << j << endl;
if(v[j+gap]<v[j]){
T temp = v[j];
v[j] = v[j+gap];
v[j+gap] = temp;
}
}
}
}
}
}
======================================================================================================
This is the main program with main(){}
======================================================================================================
include "linklist.h"
#include <iostream>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include<string>
#include <mysql++.h>
#include <iomanip>
/*
* =====================================================================================
* Class: MESSAGE
* Description: Messages from Mail Database
* =====================================================================================
*/
class MESSAGE
{
friend std::ostream & operator<<(std::ostream &, const MESSAGE&);
public:
/* ==================== LIFECYCLE ======================================= */
inline MESSAGE():id_("blank"), date_("blank"), from_("blank"), subject_("blank"), message_("blank") {} /* constructor */
inline MESSAGE(int a) {
if(a != 0)
std::cerr << "Failed Construction: Used and interger: Line==> " << __LINE__ << std::endl;
} /* constructor */
inline MESSAGE(std::string a,std::string b,std::string c,std::string d,std::string e):id_(a), date_(b), from_(c), subject_(d), message_(e) {} /* constructor */
/* ==================== ACCESSORS ======================================= */
inline const std::string& id() const { return id_;}
inline const std::string& date() const { return date_;}
inline const std::string& from() const { return from_;}
inline const std::string& subject() const { return subject_;}
inline const std::string& message() const { return message_;}
inline void id(std::string &par ){id_ = par;}
inline void date(std::string &par){ date_ = par;}
inline void from(std::string &par){ from_= par;}
inline void subject(std::string &par){ subject_ = par;}
inline void message(std::string &par){ message_ = par;}
/* ==================== MUTATORS ======================================= */
/* ==================== OPERATORS ======================================= */
MESSAGE operator()(std::string a, std::string b, std::string c, std::string d, std::string e){ //This is NOT a CONSTRUCTOR
id(a);
date(b);
from(c);
subject(d);
message(e);
return *this;
}
bool operator<(MESSAGE const val2){
if(this->subject() < val2.subject()) {
return true;
} else{
return false ;
}
}
protected:
/* ==================== DATA MEMBERS ======================================= */
private:
/* ==================== DATA MEMBERS ======================================= */
std::string id_;
std::string date_;
std::string from_;
std::string subject_;
std::string message_;
}; /* ----- end of class MESSAGE ----- */
std::ostream & operator<<(std::ostream& outbound, const MESSAGE& mes){
outbound << "ID ==> " << mes.id() << std::endl << "Date==> " << mes.date() << std::endl<< "From==> " << mes.from() << std::endl << "Subject==> " << mes.subject()<< std::endl << mes.message() << std::endl;
return outbound;
}
int main(int argv, char **argc){
if(1){ //create a scope to trigger destructors
CHAINLIST::LIST<int> mylist;
mylist.display();
// int size = mylist.size();
std::cout << "Size of the List at the start is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(1);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(1);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(2);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(4);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(8);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.insert(16);
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.remove_front();
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
mylist.remove_all();
std::cout << "Size of the List is: " << mylist.size() << std::endl;
mylist.display();
std::cout << "****Testing find****" << std::endl;
int a = 0; int b = 1;int c;int index = 0; const int max = 50000;
mylist.insert(b);
std::cout << "Max Int is ==>" << INT_MAX << std::endl;
for(c=b+a;c < INT_MAX ; index++){
mylist.insert(c);
a = b;
b=c;
c=b+a;
if(c < b){
mylist.insert(b);
break; //This only happens when we get larger than an int
}
std::cout << "Size of the List is: " << mylist.size() << std::endl;
std::cout << "Index 4 is ==> " << mylist[4] << std::endl;
std::cout << "Index 3 is ==> " << mylist[3] << std::endl;
std::cout << "Index 500000 is ==> " << mylist[500000] << std::endl;
mylist.display();
}
CHAINLIST::NODE<int> * found = mylist.find(1836311903);
if(found != NULL)
std::cout << "Found ==>" << found->value() << " at " << found << std::endl;
else
std::cout << "1597 not found\n";
found = mylist.find(23);
if(found != NULL)
std::cout << "Found ==>" << found->value() << " at " << found << std::endl;
else
std::cout << "23 not found\n";
std::cout << "int b is ==>" << b << std::endl;
for (index = 0; index < max; index++){
found=mylist.find(index);
if(found != NULL)
std::cout << "Found ==>" << found->value() << " at " << found << std::endl;
//else
// cerr << index << " not found\n";
if (index > b) break;
}
mylist.remove_all();
std::cout << "*********** Test find_all ******************" << std::endl;
std::cout << "Create a huge link list of random numbers between 1-100\n";
int ran;
srand(12345);
for (index = 0; index < 50; index++){
ran = rand();
ran = ran % 101;
mylist.insert(ran);
// std::cout << "random ==>" << ran << std::endl;
}
mylist.insert(48);
mylist.insert(48);
mylist.insert(0);
mylist.insert(2);
mylist.insert(4);
mylist.insert(48);
mylist.insert(48);
mylist.insert(5);
mylist.insert(5);
mylist.insert(6);
mylist.insert(7);
mylist.insert(3);
mylist.insert(8);
mylist.insert(48);
mylist.insert(3);
mylist.insert(3);
mylist.insert(3);
mylist.insert(4);
mylist.insert(5);
mylist.insert(46);
mylist.insert(2);
mylist.insert(6);
mylist.insert(48);
std::cout << "List Size ==>" << mylist.size() << std::endl;
int cont48 = 0;
CHAINLIST::NODE<int> * tmp = mylist.find_all(48);
while(tmp != NULL){
//std::cout << "Found " << tmp->value() << " at ==>" << tmp << std::endl;
tmp = mylist.find_all(48, tmp);
cont48++;
}
std::cout << "******TESTING removing of an item****************" << std::endl;
std::cout << "Size is ==>" << mylist.size() << std::endl;
std::cout << "48 is in this list " << cont48 << " times\n";
// mylist.display();
tmp = mylist.find_all(48);
CHAINLIST::NODE<int> * tmp2 = tmp;
while(( tmp=mylist.find_all(48,tmp))){
// std::cout << "while::tmp not NULL\n";
// std::cout << "DELETING ==>" << tmp2 << " VALUE==> " << tmp->value() << std::endl;
mylist.remove_item(tmp2);
// std::cout << "Node is ==>" << tmp << std::endl;
tmp2 = tmp;
}
mylist.remove_item(tmp2);
// mylist.display();
std::cout << "Size is ==>" <<mylist.size() << std::endl;
// mylist.remove_all();
std::cout << "size + deletes = " << (mylist.size() + cont48) << std::endl;
std::cout << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
mylist.insert(NULL,23);
mylist.insert(NULL,23);
mylist.insert(NULL,23);
// mylist.display();
//std::cout << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
mylist.insert(23);
mylist.insert(23);
mylist.insert(23);
mylist.display();
//std::cout << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
tmp = mylist.find(23);
std::cout << "*************found********************************" << __LINE__ << std::endl;
//std::cout << tmp << "\t" << tmp->value() << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
mylist.insert(tmp,1111);
//std::cout << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
// mylist.display();
tmp = mylist.find_all(23,tmp);
//std::cout << "*************found********************************" << __LINE__ << std::endl;
//std::cout << tmp << "\t" << tmp->value() << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
mylist.insert(tmp,1111);
//std::cout << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
// mylist.display();
while((tmp = mylist.find_all(23, tmp))){
//std::cout << "*************found********************************" << __LINE__ << std::endl;
//std::cout << tmp << "\t" << tmp->value() << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
mylist.insert(tmp,1111);
//std::cout << tmp << "\t" << tmp->value() << "*************TESTING SOME INSERTS********************************" << __LINE__ << std::endl;
}
while((tmp = mylist.find_all(23, tmp))){
std::cout << "tmp==> "<< tmp << "\t" << "tmp-value()" << tmp->value() << std::endl;
std::cout << "*************WHile Loop TESTING SOME INSERTS findall********************************\n";
std::cout << tmp->value() << "\t" << (tmp->next())->value() << std::endl;
}
tmp=NULL;
while((tmp = mylist.find_all(1111, tmp))){
std::cout << "tmp==> "<< tmp << "\t" << "tmp-value()" << tmp->value() << std::endl;
// std::cout << "*************While Loop findall********************************\n";
std::cout << tmp->value() << "\t" << (tmp->next())->value() << std::endl;
}
mylist.display();
tmp=NULL;
mylist.insert(tmp,8888);
mylist.insert(8888);
std::cout << "inserted\n\n\n";
mylist.display();
while((tmp = mylist.find_all(8888, tmp))){
// std::cout << "tmp==> "<< tmp << "\t" << "tmp-value() " << tmp->value() << std::endl;
// std::cout << "*************While Loop TESTING findall********************************\n";
std::cout << tmp->value() << "\t" << (tmp->next())->value() << std::endl;
}
mylist.display();
}//End of Scope - Watch for the Destructors
CHAINLIST::LIST<int> * mylist = new CHAINLIST::LIST<int>;
mylist->display();
mylist->size();
CHAINLIST::LIST<std::string> * mylist2 = new CHAINLIST::LIST<std::string>;
mylist2->insert("Hello World");
mylist2->insert("I love Schmueli Bear");
mylist2->insert("Francine Robin is great");
mylist2->insert("Life is wonderful");
mylist2->insert("Shani is a superstar");
mylist2->insert("Aviva is the blondie girl");
mylist2->insert("C++ is EASY!!");
mylist2->insert("What?");
mylist2->insert("Taly is my big girl");
mylist2->insert("Dovid Shimon is the MAN");
mylist2->insert("Hernandez laces a long line drive..");
mylist2->insert("Lets Go Mets");
mylist2->display();
std::cout << "Number of Strings is ==> "<< mylist2->size() << std::endl;
CHAINLIST::NODE<std::string> * found = mylist2->find("Lets Go Mets");
std::cout << "We Found " << found << " ==>" << found->value() << std::endl;
mylist2->sort(*mylist2);
std::cout << "Number of Strings after sort is ==> "<< mylist2->size();
found = mylist2->find("Lets Go Mets");
std::cout << "We Found " << found << " ==>" << found->value() << std::endl;
mysqlpp:: Connection handle("rubenmail", 0, "ruben", "************************");
if( handle.connected() ){
std::cout << "connected\n";
}else{
std::cout << "no Connection: " << handle.error() << std::endl;
return 1;
}
mysqlpp::Query ask(&handle,true, "select id, day, fromit, subject, message from postings where fromit like \"%francal%\"");
mysqlpp::Query ask2(&handle,true, "select id, day, fromit, subject, message from postings where fromit like \"%2013156062%\"");
mysqlpp::StoreQueryResult::const_iterator place;
mysqlpp::Row row;
mysqlpp::StoreQueryResult fran;
mysqlpp::StoreQueryResult fran_text;
if((fran = ask.store()) && (fran_text = ask2.store())){
MESSAGE * onemail = new MESSAGE();
//std::cout << onemail->id() << onemail->date() << onemail->from() << onemail->subject() << onemail->message() << std::endl;
//MESSAGE * twomail = new MESSAGE("Oh ", "Hello ", "DOLLY. ", "Oh ", "Hello");
//std::cout << twomail->id() << twomail->date() << twomail->from() << twomail->subject() << twomail->message() << std::endl;
//(*onemail)("Oh ", "Hello ", "DOLLY. ", " I'm all alone", " We Code for Food");
//std::cout << onemail->id() << onemail->date() << onemail->from() << onemail->subject() << onemail->message() << std::endl;
CHAINLIST::LIST<MESSAGE> mylist3;
for(place = fran.begin(); place != fran.end(); ++place){
row = *place;
//std::cout << "\t" << row[0] << "\t" << row[1] << "\t" << row[2] <<"\t" << row[3] <<"\t" << std::endl;
std::cout << "Got this far " << __LINE__ << std::endl;
//std::string tmp = row[0].c_str();
//std::cout << tmp << std::cout;
(*onemail)(row[0].c_str(), row[1].c_str(), row[2].c_str(),row[3].c_str(),row[4].c_str());
mylist3.insert(*onemail);
}
for(place = fran.begin();place != fran.end(); ++place){
row = *place;
mylist3.insert((*onemail)(row[0].c_str(),row[1].c_str(),row[2].c_str(),row[3].c_str(),row[4].c_str()));
}
mylist3.display();
std::cout << "Number of Messages is ==> "<< mylist3.size();
mylist3.sort(mylist3);
std::cout << "Number of Messages after sort is ==> "<< mylist3.size();
std::cout << "Sorted Order By Subject **************************************************************************" << std::endl;
mylist3.display();
}
return 0;
}
========================================================================================================================
The problem is when I try to return NULLS or Zeros from accessory methods, especially with
the operator[] overload in templates of the type message. These are needed because the end
of the linked list is marked with zero values. First I was returning 0's.
The reference returns in operator[] didn't like that saying they were Temporary objects when
returned by NODE.value(). So I added a NODE.value_ref(). But when the template class type
is std::string and i try to return 0, it says that class string is not able to determine which operator= to use
I tried to add an unk err member, but I can't initializing it according to C++ iso standard, and it is still ambigious to
to string class when I try to assign it.
I'm just frustrated to no end at this point and need advise as to how to code this rationally.
Ruben