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

Tools

Tech Tips


July, 2004: Tech Tips

George is a software engineer in the System Design and Verification group at Cadence Design Systems. He can be reached at georgefrazieryahoo.com.


Null Iterator Type for STL

by Dan Shappir

shappirmath.tau.ac.il

Sometimes it's worthwhile to do nothing. That is why many operating systems let you redirect output to null devices. Similarly, C/C++ functions that use pointers for output parameters often allow passing NULL as an indication that a particular value should be discarded. If possible, such a value shouldn't even be calculated in the first place. Given how useful and widespread this idiom is, I was surprised to find it missing from the Standard Template Library (STL).

STL uses iterators as an abstraction that lets a section of code read data from a variety of sources. For example, you can use the find algorithm to search the members in any STL collection, the characters in an std::string, and also inside a file, using the std::istream_iterator. Likewise, output iterators let a section of code write data to a variety of destinations. What STL lacks is an output iterator type that simply discards any data written into it. Ideally, such an iterator should be defined in such a way that would allow an optimizing compiler to discard the entire calculation of the output values.

I created such an iterator, which I've named null_iterator (Listing One). I would have liked to put this iterator in the std namespace, but the C++ Standard prohibits the placement of programmer-defined identifiers into that namespace. Using null_iterator, I can create generic algorithms that, among other operations, also generate optional output (logs). When this output is needed, I will direct it to a standard iterator. When it isn't needed, I direct it to a null_iterator.

For example, the following code does absolutely nothing:

std::copy(someContainer.begin(),
someContainer.end(), null_iterator());

Indeed, with optimizations enabled, the compiler should emit no code for it at all. null_iterator is implemented in such a way that it supports every type of output data. Because the STL implementation in Microsoft VC6 was not fully standard compliant, I had to use conditional compilation to support that compiler.

Debug Formats in GCC

by George F. Frazier

georgefrazieryahoo.com

One of the "black arts" of GCC configuration and usage is the interaction between the debug format GCC outputs and its consumption by open-source tools like GDB and proprietary tools such as IBM's (aka Rational's) Purify. For example, if you have a language tool and you ship or bundle a version of GCC so that you know your users are going to use the same version you used to build your libraries with, it is important to be able to support the basic debugging tools that those customers are accustomed to using. If you are taking the time to "ship" GCC, you are probably also either shipping or recommending a specific version of GDB as well.

A common scenario that causes problems is when GCC is configured to use Dwarf 2 as the default debug format for better symbol table info in GDB. The choice of debug format is highly platform specific, but Dwarf 2 can buy you extra debug info if you are using some of the more common platforms such as Solaris and Linux. You configure GCC to default to Dwarf 2 at configure time by specifying —with-dwarf2. Specify that the compiler should use DWARF 2 debugging information as the default. Most platforms default to stabs otherwise.

The problem here is that Purify doesn't understand Dwarf 2 so if you load up your code in Purify, you won't have line number info, source annotation, or the ability to descend into a function hierarchy in the GUI.

The simple solution here is to instruct your users to build their code with the -gstabs or -gstabs+ option to GCC. You are in effect robbing Peter to pay Paul: GDB info suffers to some extent if you are relying on Dwarf 2 and have compiled your libraries that way; but most users are willing to do a special build for Purified info and then switch back to the standard compile options once they have fixed memory leaks, memory corruption, or whatever they are hunting down in Purify. The moral here is that for symbol table formats, one size doesn't fit all, but GCC provides an excellent level of control both at the configure and compile stage for determining the format for debug output. Make sure you understand your requirements first and then communicate them to your customers.

Enumerating Registry

Subkeys in D

by Matthew Wilson

matthewsynesis.com.au

In the implementation of the D.win32.registry module for Phobos (the D Standard Library, http://digitalmars.com/d/), I had handled the enumeration of registry subkeys by using a helper function _Reg_EnumKeyName(). This function originally performed the task of hiding all the un- needed parameters to the Win32 API C function RegEnumKeyExA(), and was defined as in Example 1(a).

The client code that used this helper for the lookup or enumeration of keys was contained within methods of several of the classes in the registry module, as shown in Example 1(b).

This function uses another helper function _Reg_GetNumSubKeys(), which uses the Win32 API C function RegQueryInfoKeyA() to determine the number of sub-keys and the maximum length of the names of the subkeys. This enables the array sName to be allocated accordingly; see Example 1(c).

The problem is that, in a very few cases, the registry API tells lies. On my machine, there were four keys for which the maximum subkey length was misreported, leading to the name lookup failing with the error ERROR_MORE_DATA. (Interestingly they were all within HKEY_LOCAL_MACHINE\SYSTEM\ControlSet00x, which makes me wonder whether they crept in during the backup of CurrentControlSet.) The only answer to this kind of bug is to make a workaround that will work for all operating-system versions, broken or not. The answer is in the new form of the _Reg_EnumKeyName() helper in Listing Two.

The new version of the function requires that a D character array (char[]) is passed as an inout parameter, whereas the original form just took a pointer to a fixed buffer. This change allows the buffer to be changed within the helper function, as you can see in the case where RegEnumKeyExA() returns ERROR_MORE_DATA. The array is resized by doubling in size until ERROR_MORE_DATA is not returned, using D's helpful array-length assignment.

DDJ



Listing One

class null_iterator
#if defined(_MSC_VER) && _MSC_VER < 1300
      : public std::iterator
#else
      : public std::iterator
#endif
{
public:
      typedef void container_type;
private:
      class proxy
      {
      public:
            template
                  proxy& operator=(const _Ty&)
            { return *this; }
      };
public:
      proxy operator*()
            { return proxy(); }
      null_iterator& operator++()
            { return *this; }
      null_iterator operator++(int)
            { return *this; }
      bool operator==(const null_iterator&) const
            { return true; }
      bool operator!=(const null_iterator&) const
            { return false; }
};
Back to article


Listing Two
private LONG _Reg_EnumKeyName(  in    HKEY    hkey
                              , in    DWORD   index
                              , inout char[]  name
                              , out   DWORD   cchName)
in
{
  assert(null !== hkey);
  assert(null !== name);
  assert(0 < name.length);
}
body
{
  LONG    res;
  for(;;)
  {
      cchName = name.length;
      res = RegEnumKeyExA(hkey, index, name
              , cchName, RESERVED, null, null, null);
      if(ERROR_MORE_DATA != res)
      {
          break;
      }
      else
      {
          // Increase the size of the buffer and try again
          name.length = 2 * name.length;
      }
  }
  return res;
}
Back to article


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.