Boost logo

Boost :

From: John Maddock (john_at_[hidden])
Date: 2008-02-28 04:02:41


Johan Råde wrote:
>> 2) I'm not completely sure about the "legacy" flag: shouldn't the
>> facet just read in everything that it recognises by default? Or
>> maybe we should flip the meanings and "legacy" should become
>> "strict_read" or "nolegacy" or something - I'm not that keen on
>> those names, but Boosters can usually come up with something snappy
>> when asked :-)
>
> There are cases where the legacy flag could change the meaning of a
> file.
> For instance, if you set the legacy flag, and parse the string "1#2",
> then "1#" will be interpreted as the beginning of "1#INF" or some
> other Visual Studio nonsense. Once the parser gets to '2', it will
> realize its mistake,
> but when you read using stream iterators it is impossible to
> backtrack,
> so the parser will set the failbit of the stream.
>
> So the legacy flag can be a little dangerous.
> This should of course be pointed out in the docs.

Ah, I see, in that case it's probably best to leave as is, and add an
"admonishment" to the docs to point this out.

>> 4) I think the flags are useful, but would be a lot nicer as iostream
>> manipulators - although I accept this may not work with lexical_cast
>> :-(
>>
>> BTW what was the issue that would require separate file compilation
>> for manipulators?
>
> It is about four years since last time I defined my own manipulators,
> but this is how I remember it:
>
> When you define a manipulator you need to store some state
> information with the stream. Streams contain an integer array that
> should be used for that purpose.
> The nonfinite_num_facets would need to reserve a position in those
> arrays.
> That is done by calling std::xalloc, exactly once,
> and storing the returned integer value in a global integer variable.
> You must make sure that there is exactly one instance of that
> variable.
> If you pass stream objects between different DLL's,
> then you must make sure that all the DLL's share the same instance of
> that variable.
> Can that be guaranteed without having a cpp file,
> and compiling that file as a DLL that is used by the other DLL's?

This is tricky, the usual way would be to use boost::call_once:

template <bool dummy>
struct iostream_data
{
private:
static int& get_iword_index()
{
    static int index;
    return index;
}
static void init()
{
    get_iword_index() = std::ios_base::xalloc();
}

public:
static void index()
{
    static boost::once_flag f = BOOST_ONCE_INIT;
    boost::call_once(&iostream_data<dummy>::init, f);
    return get_iword_index();
}

};

Then the manipulator can use iostream_data<true>::index() to obtain the
index of iword it wants to use.

The problem as you correctly point out is with DLL's: I'm fairly sure that
on Unix (or Linux anyway) the shared library loader will resolve duplicate
symbols so that just one is active in the program - that way only one
instance of iostream_data<dummy> will be active and everything should work
OK. On Windows though you could end up with separate instances of
iostream_data<dummy> in each dll, which would be bad news if you expect to
pass iostreams between them :-( The only - somewhat inelegant - solution I
can think of is to define a pair of macros to import/export
iostream_data<dummy> so users can control it's instantiation.

Cheers, John.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk