Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

We Have Mail


January 2002/We Have Mail


Letters to the editor may be sent via email to [email protected], or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.


Re: Steve Dewhurst’s August 2001 “Common Knowledge” column

When the compiler eliminates the code in the if part of if ( false ), the resulting executable of the release version and the debug version are different, just as is the case if the #ifndef construct is used. In other words, you still have to compile the code just as many times with either construct (ignoring syntactical errors in the #ifndef case, which are missed when NDEBUG — or whatever the controlling macro is — is defined). The real problem seems to be that side effects in the code, which are either present or absent depending on the NDEBUG or const bool debug, influences the behavior of the code. I do not see the gain in your proposal, except that it is — under the right circumstances — aesthetically more pleasing, which helps to concentrate on the code while reviewing it, thus improving the chance of detecting bugs. In other cases (e.g., h-files), it may be more attractive to stick to the #ifdef mechanism. Please, tell me if I missed your point.

Nico Valster

Nico,

It’s true that in both cases the effect on the generated object code is largely the same, in that the code is eliminated. What differs is the mechanism by which the code is eliminated, and the likelihood that each mechanism will produce a correct result. In the case of the #ifdef version, the fallible human programmer has decided that the meanings of the debug/no-debug versions are identical except for some additional debugging behavior. In the version that depends on the compile-time evaluation of a constant-expression, the infallible compiler ensures that there will be no semantic change when the code is eliminated. The elimination comes late in translation, when the source code has been not only parsed, but has undergone a static semantic check. Before the code elimination takes place, the compiler’s static checking will have propagated any possible side effect of the eliminated code, and its removal is therefore provably safe. This safety is guaranteed even as the code is maintained.

Consider an analogous problem that often arises with the standard assert macro. The experienced original programmer knows that assert expressions should have no side effects.

// ...
a = b;
assert( a );
//...

Later maintainers may not be as careful, valuing brevity over correctness.

//...
assert( a = b );
//...

This kind of thing can’t happen if we let the compiler handle the elimination.

It is true, as you point out, that we will still have two different sets of behaviors depending on the compile-time value of the debug flag.

const bool debug = false;
//...
if( debug )
    // probably elimination...

However, this is true of any conditional or polymorphic code and is certainly no more complex than the case in which the value of the debug flag is not determinable at compile time.

const bool debug = 
    getDebugValueFromCommandLine();
//...
if( debug )
    // probably no elimination...

The only difference between these two versions is that the compiler is better capable of optimizing the first. Use of a debug variable in preference to a #ifdef allows the code turn debugging on at compile time, off at compile time, or allow a run-time on/off switch. All three programs will have the same meaning — up to whatever optimization the compiler is capable of applying. This is the case for conditional code in general.

I agree with your point about aesthetics. As a practical matter, use of #ifdef with a single symbol (like NDEBUG) is more problematic than a simple conditional, but generally does not cause insurmountable problems. However, the resulting code is more difficult to read and maintain. The real problems arise when the #ifdefs employ very complex expressions and are deeply nested. In effect, we have a pre-compile (preprocessor) conditional structure that overlays whatever conditional structure is present at compile time and run time. The resulting complexity is a mess both aesthetically and practically. Even in the case of header files, use of #ifdef is generally a poorer approach than a redesign.

Steve Dewhurst


Dear CUJ,

Regarding Mark Nelson’s article “A C++ Debug Stream for Win32” in CUJ (September 2001), I’d like to add one or two comments.

Like the author, I’ve been in the business long before Win-whatever came up, and everyone from the past has at least written 3...8 debug-output-libraries, sometimes in C, later in C++. However (let me get to the point): there is a far easier way to get the results described in this article. The simple solution is use printf; use cout << something. You don’t see the output when running a GUI-application; it goes to the sink, but, hey, simply redirect the output on a command line (usually called DOS box) to a file, and there it is. It even works with complex MFC apps and is more or less thread-safe because the output is line-buffered (imagine the authors output with, say, 20 threads or so). printf works; cout works; what else do you need? I am not talking about performance, neither in this aritcle, nor in my solution. All the output is formatted before it goes (99%) to the sink. If you really want a console output, which I don’t prefer (because the important line is generally the line just scrolled off the window), you can pipe the output to some other program, which uses named pipes or even send the output via TCP/IP to your machine. One more advantage: it’s not platform specific, at least it will compile and run on Unix machines (whatever happens there with the output). As far as I remember, it even works on OS/2 (ever heard of it?). Conclusion: it’s fun to write (debug) classes, but sometimes you can spend some more time with your family, because it’s already there.

Regards

Andreas Gruen
Notes Development GmbH
Hannover, Germany
[email protected]

Hi Andreas,

Thanks for your comments on the article. While it’s true that in modern incarnations of Windows, cout and printf can be used with no harm, they aren’t much help in debugging unless you write some additional glue code. My goal was to have quick and easy text mode output that I could enable and disable programmatically, and the code in the article does that without minimal effort.

Using standard input and output can accomplish the same thing if one writes a bit of glue code. From the perspective of the code writer, there’s not much difference though. If my debug statement looks like this:

foo << "Current value is: " 
    << value 
    << endl;

I don’t really care whether foo is a contrived class or simply a reference to cout. The level of effort is the same regardless!

Mark Nelson


Recently I wrote about a correction [in “CUJ’s Most Loyal Readers,” November 2001] regarding the term “Brain Damage” with respect to the “BDS” C compiler — in particular to correct an inadvertent “d” that crept in during the editing process, turning it erroneously into “Brain Damaged.” [This has now been updated on our website — ap.]

I must now also report another error, this one my own. Leor Zolman recently sent me an email wherein he pointed out that I was in error in attributing “Brain Damage” (as in BDS C) to the character with that name in Doonesbury. It turns out that the “Brain Damage” in BD Software had a different origin. Leor’s website, <www.bdsoft.com>, has a link to a site containing a biographical sketch, which, presumably, has an accurate description of the origination of the name.

Thanks.

Jay R. Jaeger


Re: C++ Experts Forum

So glad you kept such incredible sources of knowledge available to us mortals! I missed reading their articles in C++ Report and am glad you picked up their writings. Keep this web page running!

Jeffrey T. Bush
Capt USAF


Hello,

I downloaded the code for Michael Yoder’s article in the March 2001 issue, but it doesn’t compile.

Thanks,

Robert Schwartz

Hi Robert,

Unfortunately, Microsoft’s Visual C++ doesn’t support partial ordering of function templates. You can still use the techniques described in the article, although it disallows capturing groups of types at compile time with a policy. This is described in the section of the article entitled “Function Templates and ANSI Compliance.” For this example, the change to user.cpp would be to replace these lines:

template<class T>
void policy
  (const MyContainer<Element2<T> > * c)

with:

template<>
void policy
  (const MyContainer<Element2<int> > * c)

which results in the output:

D:\Example3>cl -GX user.cpp
Microsoft (R) 32-bit C/C++ Optimizing
Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998.
All rights reserved.

user.cpp
Microsoft (R) Incremental Linker
Version 6.00.8447 Copyright (C) 
Microsoft Corp 1992-1998. All rights
reserved.

/out:user.exe
user.obj

D:\Example3>user
Performing Default Policy

Performing My Policy

This lets you set a policy for all Element2 types specialized on int, which is somewhat less powerful than setting one for all Element2 specializations.

Regards,

Michael Yoder


Regarding Fabio Lopiano’s article, “Sending Objects across Platforms” (October 2001), here is my question:

void NetBuffer::put(const char * aBuffer, 
                    size_t aSize)
{
if( theWriteCounter + aSize <= size() )
  {
    memcpy(&(theBuffer[theWriteCounter]),
      aBuffer, aSize);
  }
  theWriteCounter += aSize;
}

If I’m reading this right, in the following code when copying a string into the vector array based on the theWriteCounter variable, it is storing data all over the array. For example:

theWriteCounter = 10;
memcpy(&(theBuffer[theWriteCounter]),
  aBuffer, aSize);

After these two lines of code run, the aBuffer data will exist in the theBuffer[10] slot. That would mean that data would be randomly dispersed throughout the vector array. In this example, only slot 10 has data; if ran again and theWriteCounter equals 20, then the data would be placed in that slot skipping all of the other slots.

Thank you for your time.

Ken Fellows

Well, the data is not actually dispersed throughout the array; instead the vector is continuously filled. In fact, the memcpy doesn’t write “in the slot,” but “starting from the slot.” After all, each slot contains only one byte.

For example, when theWriteCounter is 10 and we put an integer into the NetBuffer, the aSize variable holds the value 4 (sizeof(int)), and the data is copied on the four bytes starting from the tenth slot to the thirteenth. (&(theBuffer[theWriteCounter]) means the address of the slot at the position theWriteCounter, not the slot itself.) theWriteCounter is then updated, adding 4 to it, and the next call to NetBuffer::put will copy starting from the next position, filling the buffer without gaps.

Note also that theWriteCounter variable can be changed only inside this method, that this variable can only grow, and that when we copy some data into the buffer, we add the size of the data copied to that variable.

Best regards,

Fabio Lopiano


Dear CUJ,

I very much enjoyed the article “Extending the Standard Template Library with Association Classes” by Eli Tilevich (September 2001). I think it is worth pointing out that a many-to-many mapping with relationships for each link can be described as an undirected graph with the relationships assigned to edges. Existing graph software (the Boost Graph Library at <www.boost.org>) provides the necessary accessors and iterators described in the article and hence can satisfy the requirements given in the article. Such software will usually provide additional higher-level algorithms for analysis, which depending upon the application might be of use.

Craig Hicks
Engineer, KGK Ltd.,
Tokyo, Japan

There is always more than one way to do the same thing when dealing with computer algorithms and data structures. Your observation about being able to describe a many-to-many mapping with an undirected graph is interesting. The question is whether using a graph library to represent a many-to-many association between application classes is more convenient than using a special purpose association class. While existing graph software provides the necessary accessors and iterators described in the article, using them can be quite cumbersome. For example, since every graph vertex can be of one of the two application class types participating in the association, accessing all classes of a particular type requires some additional filtering. While my many-to-many association class guarantees logarithmic complexity time for most operations, using a graph will result in only linear time: the search operation on a graph requires going over all the vertices. I don’t see much value in being able to get access to higher-level algorithms for analysis that comes with graph software. A graph used to represent associations between classes will be very disconnected in most cases. This happens because each vertex (application class object) will only have edges to the vertices it has a relationship with. I believe that these and other reasons justify the need for a special purpose many-to-many association class.

Eli Tilevich


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.