Thread View: comp.std.c++
2 messages
2 total messages
Started by David Held
Mon, 11 Mar 1996 00:38
Question about file-scope constants...
Author: David Held
Date: Mon, 11 Mar 1996 00:38
Date: Mon, 11 Mar 1996 00:38
141 lines
7342 bytes
7342 bytes
I was under the impression that a const object of any type and its data
members remained constant throughout their scope (which should be the
whole file, in this case), and that those data members were correctly
accessible from within any function in that scope. After seeing how
long my post was, I thought I had better get to the point darned quickly
at the beginning. ;>
I'm using g++ 2.7.2 on a Linux box (which I suppose shouldn't be
important in comp.std.c++, but I thought I'd include it in case someone
knows of an anomaly), and I'm trying to cobble a little exception class
together. It's really simple, so I'll include some of the declarations
here:
const int Name_Size = 65;
class Exception
{
protected:
char the_Name[Name_Size];
static Node *the_List;
public:
Exception(char *);
Exception(const Exception &);
bool operator ==(const Exception &) const;
bool operator !=(const Exception &) const;
void Raise(char * = NULL) const;
static void Entry(char *);
static void Exit(char *);
};
Now the idea is that for every function, I call Exception::Entry with a
little message giving the name of the function I have entered. The
Entry function appends a new Node to the end of a linked list pointed to
by the_List. This Node contains the name in a static size string
(char[65]). When I encounter a case where I want to raise an exception,
I call Raise with a little message stating the circumstances of the
Exception. Here's an exampe:
const Exception Memory_Error("Memory Error");
if (!(data = new int[64])) {
Memory_Error.Raise("Failed memory allocation.");
}
The Raise function goes down the_List, printing the function name in
each Node until it reaches the end. It then prints the handy-dandy
message, and throws itself (throw(*this)). If there is an Exception
catcher nearby, the Exception can be handled. Otherwise, it terminates
the program. The purpose of my class is to make it easy to debug
programs by locating the exact point where an exception occurs without
stepping through with a debugger. I can follow the function trail down
the place where the exception was raised. Here's a typical output:
Cursor out of bounds.
Demo:
Show_Menu():
Move_Cursor():
Exception Boundary Error was raised.
Here's my problem: I declare several const Exceptions in the exception.h
file, since they are ones that I expect to use in every program
(Memory_Error, Boundary_Error, File_Error, etc.). Since I have to
#include "exception.h" in a file to use the exceptions anyway, it makes
sense. I wrote a demo program where the main body is in a file called
main.cpp, and the exception testing demo is in exception_demo.cpp. I
have appropriate header files for both, and I include exception.h in
both (I set a meta-variable to make sure exception.h only gets included
once). Exception_demo.cpp contains the testing function, but apparently
when the program enters this only function of exception_demo.cpp, one of
the exceptions declared in exception.h gets mysteriously modified. This
is weird, because they are const. So, in exception.h, I have some const
Exceptions declared thusly:
const Exception
No_Exception("No Exception"),
Boundary_Error("Boundary Error"),
Memory_Error("Memory Error"),
File_Error("File Error");
When I go to raise No_Exception (i.e.: No_Exception.Raise("Testing");),
the_Name is wrong. That is, No_Exception.the_Name is not "No
Exception", like it is supposed to be. Instead, it is " Error\000ption"
followed by 52 ASCII 0's. At first, I had the_Name allocated
dynamically, inside the Exception constructor, but when I got this
problem, I changed it to static strings. The problem persisted (I
thought maybe it had something to do with destructors being called or
not having a copy constructor), so now I'm stumped.
I was under the impression that if you declare a const object of file
scope, with only statically allocated data members, that all of its data
would remain intact within that scope, and that the object would be
visible in any function entered within that scope. Apparently, someone
is tampering with my data, and it appears that they are breaking the
rules. There are no assignments to Exception::the_Name after the
constructor is called. There is no conceivable way that my code could
be modifying the object data.
There are a few interesting phenomena to note: the first const
Exception is the only one that gets tampered with. All of the rest of
them remain the same. I have juggled them around, changed their names,
everything I could think of. The first one is always the only one that
changes. When I traced through the code with gdb, No_Exception (which I
used to use when I was passing Exceptions back through functions,
instead of throwing them--didn't have 2.7.2) is fine all the way to the
point where exception_demo.cpp is entered, and void Exception_Demo(void)
is called (all that happens up to then, is you can pick which demo you
want to run through a primitive text menu--no possible interference
here). During the call to exception_demo.cpp is when
No_Exception.the_Name gets corrupted. I know this, because I
single-stepped through the code, and inspected No_Exception.the_Name
both before the call, and after the first line of Exception_Demo(void)
(which happens to be an innocent cout statement). The name appears to
get corrupted during the call. However, I believe that it is "magically
restored" back in main.cpp. This indicates to me that some foul copy of
No_Exception is used in exception_demo.cpp (and thus Exception_Demo()).
Is this true? I have a correct copy constructor defined, so I would
think that even if it made a temporary, that it would do so correctly
(after all, all the other exceptions work fine).
In summary, I was under the impression that a const object of any type
and its data members remained constant throughout their scope (which
should be the whole file, in this case), and that those data members
were correctly accessible from within any function in that scope. If
anyone can help me, or clarify the defined actions of C++, I would
greatly appreciate it.
Sincerely,
Dave Held.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Re: Question about file-scope constants...
Author: Fergus Henderson
Date: Wed, 13 Mar 1996 03:40
Date: Wed, 13 Mar 1996 03:40
79 lines
4406 bytes
4406 bytes
David Held <dheld@turing.cs.stcloud.msus.edu> writes:
>I was under the impression that a const object of any type and its data
>members remained constant throughout their scope (which should be the
>whole file, in this case), and that those data members were correctly
>accessible from within any function in that scope.
That's true, provided your program does not do anything which might
constitute "undefined behaviour", such as dereferencing an
uninitialized pointer. However, from your description of the symptoms,
it sounds like your program is invoking undefined behaviour at some
point, in which case all bets are off.
The C++ standard allows implementations to detect such errors at
run-time, but it does not require them to do so. Compilers are not
required to place const objects in read-only memory, so if your program
assigns via a stray pointer, your const objects could be overwriten.
(Practically speaking, I would suggest that you get hold of an
implementation which does perform run-time checking. They're very
useful for debugging problems like this.)
>class Exception
>{
[...]
>public:
> Exception(char *);
[...]
>};
[...]
>const Exception Memory_Error("Memory Error");
Incidentally, tying in with another thread in comp.std.c++,
it is the frequency of code like the above which means that
changing the type of string literals from `char []' to `const char []'
would break lots of code. I consider such code to be bad style --
the constructor for exception should take `const char *', not `char *' --
but until all compilers warn about it, such code will remain frequent,
even in newly developed C++-style code that makes full use of new features
such as exceptions, templates, namespaces, etc.
>Here's my problem: I declare several const Exceptions in the exception.h
>file, since they are ones that I expect to use in every program
>(Memory_Error, Boundary_Error, File_Error, etc.).
Note that in C++, declaring a global variable `const' also has the side
effect of giving that variable default internal linkage, just as if it was
declared `static'. If you want a const to have external linkage, you
need to explicitly declare it `extern'.
>I wrote a demo program where the main body is in a file called
>main.cpp, and the exception testing demo is in exception_demo.cpp. I
>have appropriate header files for both, and I include exception.h in
>both (I set a meta-variable to make sure exception.h only gets included
>once). Exception_demo.cpp contains the testing function, but apparently
>when the program enters this only function of exception_demo.cpp, one of
>the exceptions declared in exception.h gets mysteriously modified.
This effect which you observed in the debugger may be due to a different copy
of the exception coming into scope when you enter a function in a different
translation unit. As noted above, global consts default to internal linkage,
so you will get one copy of each global const for every translation unit.
>There is no conceivable way that my code could be modifying the object data.
Famous last words ;-)
In C and C++, there are hundreds of conceivable ways for code to have
undefined behaviour.
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads