Exception for doubly circular linked list

  • Thread starter Defennder
  • Start date
  • #1
Defennder
Homework Helper
2,591
5

Main Question or Discussion Point

I'm studying for an introductory C++ programming course and I'm trying to write the code for a doubly-circular linked list. To keep it simple, I had written my list to be tailored to that of a wedding dinner guest invitation list. Hence I didn't use templates at all. I've attempted to compile this code, but for some reason I just couldn't get it to compile because of some error due to exception handling.

This is the error I get(among a lot of other errors, so I figured I'll fix this one at a time, so for now just focus on the red text):
Code:
In file included from weddinglist.h:2,
                 from weddinglistimp.cpp:2:
[COLOR="Blue"]exception.h:4: error: redefinition of `class exception'
exception.h:4: error: previous definition of `class exception'[/COLOR]
In file included from weddinglistimp.cpp:2:
[COLOR="Red"]weddinglist.h:20: error: `exception' has not been declared
weddinglist.h:22: error: `exception' has not been declared
weddinglist.h:24: error: `exception' has not been declared[/COLOR]
weddinglistimp.cpp:40: error: `exception' has not been declared
weddinglistimp.cpp: In member function `void weddinglist::insert(int, const relation&, const std::string&)':
weddinglistimp.cpp:44: error: `exception' undeclared (first use this function)
weddinglistimp.cpp:44: error: (Each undeclared identifier is reported only once for each function it appears in.)
weddinglistimp.cpp: At global scope:
weddinglistimp.cpp:82: error: `exception' has not been declared
weddinglistimp.cpp: In member function `void weddinglist::remove(int)':
weddinglistimp.cpp:86: error: `exception' undeclared (first use this function)
weddinglistimp.cpp: At global scope:
weddinglistimp.cpp:110: error: `exception' has not been declared
weddinglistimp.cpp: In member function `void weddinglist::retrieve(int, relation&, std::string&)':
weddinglistimp.cpp:113: error: `exception' undeclared (first use this function)
weddinglistimp.cpp: At global scope:
weddinglistimp.cpp:121: error: `exception' has not been declared
weddinglistimp.cpp:121: error: ISO C++ forbids declaration of `exception' with no type
weddinglistimp.cpp: In function `int exception(std::string)':
weddinglistimp.cpp:121: error: `int exception(std::string)' used prior to declaration
weddinglistimp.cpp:122: error: `_message' undeclared (first use this function)
weddinglistimp.cpp: At global scope:
weddinglistimp.cpp:124: error: `exception' has not been declared
weddinglistimp.cpp:124: error: ISO C++ forbids declaration of `exception' with no type
weddinglistimp.cpp: In function `int exception()':
weddinglistimp.cpp:125: error: `_message' undeclared (first use this function)
weddinglistimp.cpp: At global scope:
weddinglistimp.cpp:127: error: `exception' has not been declared
weddinglistimp.cpp:127: error: non-member function `std::string getmessage()' cannot have `const' method qualifier
weddinglistimp.cpp: In function `std::string getmessage()':
weddinglistimp.cpp:128: error: `_message' undeclared (first use this function)
As you can see, most of the errors are related to the 'exception' class I've defined and included in the header file. So I figured if I fix that error, most of the other errors would disappear as well.

This is the contensts of 'weddinglist.h':
Note: The red text indicates the lines for which the compiler error message is displayed for.
Code:
#include <string>
#include "exception.h"
using namespace std;

enum relation { pal, coworker, relative };

class weddinglist{

    public:
        //Constructor, destructor
        weddinglist();
        ~weddinglist();

        //Small functions
        bool isempty() const;
        int getlength() const;

        //Big functions
        void insert(int index, const relation& type, const string &name)
       [COLOR="Red"] throw (exception);[/COLOR]
        void remove(int index)
        [COLOR="red"]throw (exception);[/COLOR]
        void retrieve(int index, relation& type, string& name)
        [COLOR="red"]throw (exception);[/COLOR]

    private:
        struct node{
            string _name;
            relation _type;
            node *next, *prev;};

            int size;
            node *head;
            node* find(int index) const;
};
Contents of "exception.h":

Code:
#include <string>
using namespace std;

class exception{
    public:
    exception(string errmessage);
    exception();
    string getmessage() const;

    private:
    string _message;
};
Contents of 'weddinglistimp.cpp'. This is the implementation file for the above-mentioned member functions of the doubly-circular linked list:

Code:
#include "exception.h"
#include "weddinglist.h"
#include <string>
#include <iostream>
using namespace std;

weddinglist::weddinglist()
    :size(0), head(NULL){}

weddinglist::~weddinglist()
{
    while (!isempty())
        remove(1);
} // end destructor

bool weddinglist::isempty() const
{
    return size == 0;
} // end isempty

int weddinglist::getlength() const
{
    return size;
} // end getLength

weddinglist::node *weddinglist::find(int index) const
{
    if ( (index < 1) || (index > getlength()) )
        return NULL;
    else // count from the beginning of the list.
    {
        node *cur = head;
        for (int skip = 1; skip < index; ++skip)
            cur = cur->next;
        return cur;
    } // end if
} // end find

void weddinglist::insert(int index, const relation& type, const string& name)
throw (exception)
{

    if( (index<1)||(index>(getlength()+1)))
        throw exception("Bad index specified");

    else{
        cout<<"Line 42"<<endl;
        node *ptr = new node;
        size++;
        cout<<"Line 45"<<endl;
        cout<<size<<endl;
        ptr->_name = name;
        ptr->_type = type;
        cout<<"Line 48"<<endl;

        if((index==1) || (index==size))
        {   
            node *last = find(size-1);
            cout<<"Line 53"<<endl;
            ptr->next = head;
            ptr->prev = last;
            cout<<"Line 56"<<endl;
            
            if(size!=1){
            head->prev = ptr;
            cout<<"Line 58"<<endl;
            last->next = ptr;
            cout<<"Line 59"<<endl;}

            head = ptr;}

        else{
            node *cur = find(index);
            ptr->next = cur->next;
            ptr->prev = cur;
            node *nextnode = cur->next;
            nextnode->prev = ptr;}
    }
}

void weddinglist::remove(int index)
throw (exception)
{

    if ( (index<1)||(index>getlength()))
        throw exception("Bad index specified");
    else
    {
        size--;
        if (index==1){
            node *last = find(index);
            node *cur = head->next;
            cur->prev = last;
            last->next = cur;
            delete head;
            head = cur;}

        else{
            node *cur = find(index);
            node *nodeptr = cur->prev;
            nodeptr->next = cur->next;
            nodeptr = cur->next;
            nodeptr->prev = cur->prev;
            delete cur;
            cur = NULL;}
    }
}

void weddinglist::retrieve(int index, relation& type, string& name)
throw (exception)
{
        if ( (index<1) || (index>getlength()) )
            throw exception("Bad index specified");

        else{
            node *cur = find(index);
            type = cur->_type;
            name = cur->_name;}
    }

exception::exception(string errmessage){
    _message = errmessage;}

exception::exception(){
    _message = "Out of index error default";}

string exception::getmessage() const{
    return _message;}
Now the question I have here is this: Why does the compiler say that 'exception' is undefined when I have so defined it in a user-defined header file and included it? Furthermore, why does it say (highlighted as blue text in the first CODE block) that a class redefinition has been attempted? I've only defined the class 'exception' once.
 

Answers and Replies

  • #2
Borek
Mentor
28,298
2,683
Aren't you including excteption.h twice? Both in weddinglistimp.cpp and in weddinglistimp.h?
 
  • #3
Defennder
Homework Helper
2,591
5
Commenting out either one of those #include statements makes the error highlighted in blue disappear. Thanks. But what of the error in red?
 
  • #4
283
0
Try putting the exception member function definitions in their own cpp file. Also, use header include guards, e.g.:
Code:
#ifndef SOME_UNIQUE_STRING
#define SOME_UNIQUE_STRING

#endif
That should help you avoid redefinition errors.
 
  • #5
560
1
I made a post here but then checked and found it was inaccurate. One minute.
 
Last edited:
  • #6
560
1
Commenting out either one of those #include statements makes the error highlighted in blue disappear. Thanks. But what of the error in red?
Which #include did you comment out? If you commented out the one in weddinglist.h then that is your problem, because weddinglist.h must have exception.h included (otherwise "exception" is not defined at the time weddinglist.h is interpreted). If you comment out the one in weddinglist.cpp then it appears both red and blue errors go away.

You should do the define-guard thing JaWiB suggests either way just as a matter of cleanliness.
 
  • #7
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
682
You could of course cure a lot of problems by getting rid of the throw(exception) in the prototype definitions. That is what most professional programmers have learned to do. (Read the paper cited in your other thread on exceptions for an explanation why.) The language isn't quite as good at exceptions as are other languages. The declaration is more or less eye candy in C++.

That said, you should always put in a #define guard in each and every header file you write. You will see such a guard mechanism in every single header file in the standard library include files. Look at them as a guide.

BEWARE: The standard include files use something like
#ifndef _CPP_CMATH
#define _CPP_CMATH
...
#endif

What you need to beware of: Never, ever, ever use a label that starts with underscore. If you do, you might collide with a guard label in some standard include file. A leading underscore is reserved for use by the compiler vendor. This is unenforced (and unenforceable) rule in the C and C++ standards. Don't even use a leading underscore for a variable (or element, or function, or ...) name. *All* uses of leading underscores are reserved for use by the compiler vendor. BTW, you broke that unenforced rule several times in your code. Even though the rule is unenforced you should nonetheless always obey it.
 
Last edited:
  • #8
rcgldr
Homework Helper
8,645
501
Never, ever, ever use a label that starts with underscore.
There is one exception, a struct prototype (at least in Windows environments):

Code:
struct _WEDDINGLIST{
    struct _WEDDINGLIST *next;
    struct _WEDDINGLIST *prev;
    // ...
}WEDDINGLIST, *PWEDDINGLIST;
Note, some older compilers may not support self references in structures.
 
  • #9
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
682
There is one exception, a struct prototype (at least in Windows environments):

Code:
struct _WEDDINGLIST{
    struct _WEDDINGLIST *next;
    struct _WEDDINGLIST *prev;
    // ...
}WEDDINGLIST, *PWEDDINGLIST;
Note, some older compilers may not support self references in structures.
That is a violation of the standard, pure and simple. There are no exceptions to this rule in the standard, not even for Microsoft or for Jeff Reid. The resulting code is non-compliant. It will compile, of course, because this rule is not enforced.

This rule is completely unenforceable because the C/C++ preprocessor is distinct from the language proper. (The C/C++ preprocessor language is in fact a completely different language than C or C++ proper. The X11 developers used this to their advantage in the form of the now-defunct imake.) The C/C++ preprocessor knows the difference between compiler-provided and end developer content but it does not parse that content other than to the extent needed to expand macros. By the time the preprocessor is finished, the C/C++ compiler proper does not necessarily know whether a name with a leading underscore came from a file provided by the compiler vendor or written by the end developer.
 
  • #10
Defennder
Homework Helper
2,591
5
Thanks for all your replies, guys. Unfortunately the problem still persists and I really don't know how to get rid of that error.

You could of course cure a lot of problems by getting rid of the throw(exception) in the prototype definitions. That is what most professional programmers have learned to do. (Read the paper cited in your other thread on exceptions for an explanation why.) The language isn't quite as good at exceptions as are other languages. The declaration is more or less eye candy in C++.
I kind of agree with you. From my own limited programming practice, I've had a lot less errors when I remove the throw(exception) from the prototype definitions. But unfortunately, the course I'm taking seems to encourage it, and much of the code written in the notes actually incorporates such a practice. Believe it or not, the course I'm taking actually says doing so constitutes good programming practice. See here:

http://img518.imageshack.us/img518/1084/exceptionnotesut7.jpg [Broken]

That said, you should always put in a #define guard in each and every header file you write. You will see such a guard mechanism in every single header file in the standard library include files. Look at them as a guide.
I'm rather new to C++ and to programming in general. How do I access the standard C++ library header files?


What you need to beware of: Never, ever, ever use a label that starts with underscore. If you do, you might collide with a guard label in some standard include file. A leading underscore is reserved for use by the compiler vendor. This is unenforced (and unenforceable) rule in the C and C++ standards. Don't even use a leading underscore for a variable (or element, or function, or ...) name. *All* uses of leading underscores are reserved for use by the compiler vendor. BTW, you broke that unenforced rule several times in your code. Even though the rule is unenforced you should nonetheless always obey it.
For some reason, my notes actually encourage the opposite. See:
http://img518.imageshack.us/img518/4839/underscoreej2.jpg [Broken]

Which #include did you comment out? If you commented out the one in weddinglist.h then that is your problem, because weddinglist.h must have exception.h included (otherwise "exception" is not defined at the time weddinglist.h is interpreted). If you comment out the one in weddinglist.cpp then it appears both red and blue errors go away.

You should do the define-guard thing JaWiB suggests either way just as a matter of cleanliness.
I tried out your suggestion and the problem still persists. You mean you tried it out and it works? I als tried separating the class implementation for exception.h and weddinglist.h, but still it persists.
 
Last edited by a moderator:
  • #11
Hurkyl
Staff Emeritus
Science Advisor
Gold Member
14,916
17
*All* uses of leading underscores are reserved for use by the compiler vendor.
When the identifier begins with a single underscore followed by a lowercase letter, it's only reserved at file scope; e.g. it's fair game for class members and local variables. That said...

For some reason, my notes actually encourage the opposite.
Allow me to suggest a slightly different condition: put the underscore at the end of your identifiers; that way you'll have no worries. (Just don't use a pair of underscores -- that is also reserved)
 
  • #12
Hurkyl
Staff Emeritus
Science Advisor
Gold Member
14,916
17
I would like to point out that there exists a class std::exception, which might be causing you some problems.
 
  • #13
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
682
When the identifier begins with a single underscore followed by a lowercase letter, it's only reserved at file scope; e.g. it's fair game for class members and local variables.
I say it's still off limits. It's certainly one of my rules, and since I write the rules for a bunch of other people, its their rule as well. Suppose you don't put your classes, methods, functions etc in a namespace. Your _local variable can then hide a global _local variable or _local function declared in some old C language header file. That header file might well use that _local variable or function in a macro, and that old C language header might well be #included by a C++ header file that your file #includes, directly or indirectly. Kaboom!
 
  • #14
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
682
Yikes! More on this later.

I can understand the thing with exceptions. The C++ language design community swung and missed with the exception declaration thing. Professional programmers know this from experience, but book authors and college professors often lack that experience. It makes sense to learn about exceptions, and then throw some of that knowledge away (the declaration part).

Now for the yikes. Never do this:
Code:
if ( b == 0 )
    throw string ("b is zero!!");
Always use braces. I have helped far to many people chase a bug down that turns out to have resulted from missing braces. The C/C++ community swung and missed on that as well. To see this in a book (or lecture material) is just bad. Adding braces doesn't cost anything other than a tiny bit of typing and saves a whole lot of agony.

BTW, Sorry for the exceptionally bad baseball puns. I couldn't resist throwing them out.
 
Last edited by a moderator:
  • #15
Defennder
Homework Helper
2,591
5
I would like to point out that there exists a class std::exception, which might be causing you some problems.
It appears you are right, Hurkyl. I renamed that class to listexception and all the compiler errors related to undeclared 'exception' disappeared. It is now able to compile successfully. Thanks!

On the other hand, while it could compile successfully, it gives only a semi-correct output before terminating at "Segmentation Fault". Well, at least I'm past that irritating exception handling error, so I guess what's left is for me to debug the doubly circular linked list implementation code. I added a lot of cout<<"Line XX"<<endl; to the implementation file so I could debug it.
 
  • #16
Hurkyl
Staff Emeritus
Science Advisor
Gold Member
14,916
17
I say it's still off limits. It's certainly one of my rules, and since I write the rules for a bunch of other people, its their rule as well.
But you are not the worldwide C/C++ czar of style; you have no business imposing your rule upon those outside of your authority. Nor do your rules affect what identifiers are reserved in what contexts in the standard.

I'm somewhat confused by your rant, though, since I also advised the OP not to use leading underscores.


Suppose you don't put your classes, methods, functions etc in a namespace. Your _local variable can then hide a global _local variable or _local function declared in some old C language header file. That header file might well use that _local variable or function in a macro, and that old C language header might well be #included by a C++ header file that your file #includes, directly or indirectly. Kaboom!
That's the problem with nonconforming implementations -- their behavior doesn't conform to the standard.

(I don't see the point about talking about namespaces; whether or not the function/class is in the global namespace is irrelevant to the results when a macro references a shadowed identifier)
 
Last edited:
  • #17
rcgldr
Homework Helper
8,645
501
There is (was?) one exception, a struct prototype (at least in Windows environments). Corrected by including typedef since it's a prototype:

Code:
typedef struct _WEDDINGLIST{
    struct _WEDDINGLIST *next;
    struct _WEDDINGLIST *prev;
    // ...
}WEDDINGLIST, *PWEDDINGLIST;
That is a violation of the standard, pure and simple. There are no exceptions to this rule in the standard, not even for Microsoft.
I just go with the flow. If it's good enough for Microsoft ... Here's a typical example of this usage by Microsoft in mapiwin.h:

Code:
typedef struct _WIN32_FIND_DATA {
    DWORD dwFileAttributes;
    FILETIME ftCreationTime;
    FILETIME ftLastAccessTime;
    FILETIME ftLastWriteTime;
    DWORD nFileSizeHigh;
    DWORD nFileSizeLow;
    DWORD dwReserved0;
    DWORD dwReserved1;
    TCHAR cFileName[MAX_PATH];
    TCHAR cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;
I've seen a quite a few windows app programmers use this same convention. I have looked into this and it seems that leading underscores are discouraged (when did this happen?), so I'll switch to using trailing underscores for my stuff. However I'm still stuck with all those Microsoft include files.
 
Last edited:
  • #18
D H
Staff Emeritus
Science Advisor
Insights Author
15,393
682
D H;1742841There are no exceptions to this rule in the standard said:
A retraction: There is an exception to this rule in the standard for Microsoft. Microsoft is, after all, a compiler vendor. The rule was written explicitly for compiler vendors. In plain old C, this rule essentially gives the compiler vendors a name space of their own that will not collide with identifiers in conforming end developer code.

I just go with the flow. If it's good enough for Microsoft ... Here's a typical example of this usage by Microsoft in mapiwin.h:
First off, that is essentially a system headers file. See the above retraction on the Microsoft exception to the reserved identifier rule. While there is a lot of good stuff in those system headers, making it a good idea to use system headers as exemplars, there is also something to beware of: the reserved identifier does not apply to the compiler vendors.

Secondly, any code that uses mapiwin.h is inherently non-compliant. Try porting that code to a Unix machine or a Macintosh if you don't believe me. The flip side is also true. Any code that uses X-windows or the Mac GUI is non-compliant as well; it will not compile on a Windows machine.

I've seen a quite a few windows app programmers use this same convention.
That's because they copied from the system header files and weren't cognizant of the reserved identifier rule. I was one of such people long ago until someone else pointed this rule out to me.

I have looked into this and it seems that leading underscores are discouraged (when did this happen?), so I'll switch to using trailing underscores for my stuff. However I'm still stuck with all those Microsoft include files.
The reserved identifier rule is a part of the C standard and has been for a long, long time. The C++ standards committee carried this rule forward into C++. So, when did people start discouraging the use of leading underscores? Probably when some language lawyer pointed out that the recommendation to use leading underscores is non-compliant.
 

Related Threads for: Exception for doubly circular linked list

Replies
9
Views
788
Replies
9
Views
2K
Replies
9
Views
3K
  • Last Post
Replies
20
Views
3K
  • Last Post
Replies
4
Views
1K
  • Last Post
Replies
12
Views
2K
  • Last Post
Replies
9
Views
4K
Replies
3
Views
544
Top