Listing 2

#include <iostream>
#include <ostream>
using namespace std;

// user-defined class with custom stream operators, 
// state object on the free store

// the state object
struct bracketing
{
    bracketing(char l = '(', char r = ')') : left_(l), right_(r) {}
    char left_, right_;
};
// the hypothetical complex class
class mycomplex
{
    double re_, im_;
public:
    mycomplex(double r, double i) : re_(r), im_(i) {}
    static int myindex()
    {
        static int index = ios_base::xalloc();
        return index;
    }
    static bracketing * mybrackets(ios_base &iob)

    {
        int index = myindex();
        void *&p = iob.pword(index);
        bracketing *b = static_cast<bracketing*>(p);
        if (b == NULL)
        {
            // if this is new slot, put default value
            p = b = new bracketing;
            // and register a call-back for the slot
            iob.register_callback(mycallback, index);
        }
        return b;
    }
    ostream& print(ostream &os) const
    {
        // get the stream state (maybe default) from private slot and use it
        bracketing *b = mybrackets(os);
        return os << b->left_ << re_
            << ", " << im_ << b->right_;
    }
    // other operations omitted
private:
    // call-back function
    static void mycallback(ios_base::event e,
        ios_base &iob, int index)
    {
        if (e == ios_base::erase_event)
        {
            // just destroy the state object
            delete mybrackets(iob);
        }
        else if (e == ios_base::copyfmt_event)
        {
            void *&p = iob.pword(index);
            // do not leak any exception
            try
            {
                // perform deep copy in-place
                bracketing *old = static_cast<bracketing*>(p);
                p = new bracketing(*old);
            }
            catch (...)
            {
                // in case something goes wrong, clean the slot
                p = NULL;
            }
        }
    }
};
ostream & operator<<(ostream &os, const mycomplex &cplx)
{
    return cplx.print(os);
}
// convenience modifier with inserter operator
bracketing setbrackets(char l, char r)

{
    return bracketing(l, r);
}
ostream & operator<<(ostream &os, bracketing b)
{
    // set the stream state in the private slot
    // a simple value-based assignment will do
    bracketing *pb = mycomplex::mybrackets(os);
    *pb = b;
    return os;
}
int main()
{
    mycomplex c(3.14, 2.71);
    // use default bracketing style
    cout << c << endl;
    // change the bracketing style
    cout << setbrackets('[', ']');
    cout << c << endl;
}