Now let’s say you want to pass a class’s member function to call_functor() above, as in:
1
2
3
4
5
6
7
classC{
voidfoo() { std::cout <<"foo()\n"; }
};
C c;
call_functor(/\* What do I put here? c.foo and &C::foo don't work \*/);
The STL has a pointer-to-member function adapter called std::mem_fun() which almost gets us there. Unfortunately, it doesn’t quite meet our needs because it requires us to pass a pointer to an instance of C, as in:
Answer: my_pair cannot be used as a key for a STL map because the operator< violates the rule of strict weak ordering. More specifically, the operator is not antisymmetric. Consider the following:
I recently wrote a piece of code that looked something like the following:
1
2
3
4
5
6
7
8
9
10
11
staticconstint NUM_TOTAL_VALUES = ...;
typedef ... T;
// Create vec and reserve NUM_TOTAL_VALUES spaces for later insertion
std::vector<T> vec(NUM_TOTAL_VALUES);
// Insert values into vec
for (int i =0; i != NUM_TOTAL_VALUES; ++i)
vec.push_back(...);
// vec should now have NUM_TOTAL_VALUES values in it (but doesn't!)
#pragma unmanaged
classStream { ... }; // Conceptual stream class
classStreamWriter{
public: StreamWriter(Stream* pStream) : m_pStream(pStream) {}
~StreamWriter() { /* Use m_pStream in some way */ }
...
private: Stream* m_pStream;
};
voidf()
{
Stream stream;
StreamWriter streamWriter(&stream);
// Use streamWriter
// streamWriter is destroyed
// stream is destroyed
}
Note that StreamWriter’s destructor uses m_pStream (perhaps by flushing the stream). This means that the order of destruction is important — StreamWriter must be destroyed before its underlying Stream is.
Surprisingly, it depends! As I would expect, on many operating system / compiler combinations (such as gcc version 3.4.4 20050721 (Red Hat 3.4.4-2) as tested by Keith Garner), the dereference of the null pointer leads to a segmentation fault. However, both Microsoft Visual Studio 6.0 and Visual Studio .NET 2003 print the message Caught exception. and exit gracefully. Strange!
This is part 14/14 of my Implementing IXmlWriter post series.
Today I will add support for writing the generated XML to a C++ stream to last time’s IXmlWriter.
Finally the reason why I’ve insisted on calling this series IXmlWriter (instead of StringXmlWriter) should become clear: I’ve been planning on supporting writing the generated XML to more than just a string. Specifically, today I will add the ability to write the XML to a C++ ostream object, a base class in the C++ iostream library which defines a writable stream.
The idea behind the pimpl idiom is to hide as much of the class definition as possible in order to avoid requiring users of the class to recompile if the class’s private members are changed. It is accomplished by moving all private members (functions, data, etc.) into a separate class (called the implementation or pimpl class) hidden from the class definition, and replacing these members with an opaque pointer to a forward declaration of this class. It works because a C++ compiler does not need to have the full definition of a class visible in order to allocate space for a pointer to the class; every pointer is a constant, fixed size (often 4 bytes).
Pretty-printing is the addition of whitespace at predetermined locations to make the resulting XML easier to read than when it is all on one line. In the .NET Framework’s System.Xml.XmlTextWriter class, it is supported by the properties Formatting, which allows you to enable or disable pretty-printing; Indentation, which allows you to specify how many whitespace characters indentation should use; and IndentChar, which allows you to specify the whitespace character to use for indentation. For IXmlWriter, I instead chose to expose these features exclusively through the constructor. This frees me from the worry of a user trying to change these properties after IXmlWriter has already begun writing XML, which could produce awkward results. Default parameters are used to make the use of pretty-printing optional and straightforward.
Namespaces are defined by the W3C recommendation Namespaces in XML. Using namespaces requires two parts: a namespace declaration, which associates a prefix with a namespace name (a user-defined, ideally globally-unique string which defines the namespace, often in the form of a URL); and the assignment of XML elements and attributes to this namespace by using the aforementioned prefix.
Comments MAY appear anywhere in a document outside other markup; in addition, they MAY appear within the document type declaration at places allowed by the grammar.
Considering this, we should allow writing comments in virtually every WriteState that the IXmlWriter can be in. In fact, some quick thought confirms that we should allow it for every WriteState but WriteState_Attribute, as a comment cannot be legally represented between the quotation marks which delimit an attribute value. With this in mind, here’s the test case I wrote: