Boost logo

Boost :

From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-10-26 01:06:46


Alberto Ganesh Barbati wrote:
> Hi,
>
> I started using the iostreams library for a pet project. I thinks
> it's a great piece of software.

Thanks!

> However, I immediately stumbled in
> what I think it may be a defect. Consider this simple source device:

> struct Source : boost::noncopyable
> {

    <snip>
> };
>
> int main()
> {
> boost::iostreams::stream<Source> s(0);
> }

> the boost::noncopyable up there has been put because the device keeps
> handles to OS resources whose duplication can be very expensive.

This is a common situation. For example, the zlib filters have to manage
non-copyable z_stream structures, and the file wrappers (e.g. file) manage
non-copyable stream buffers from the standard library. There are two ways to
handle this situation with the current library design:

 1. Use reference counting. shared_ptr makes this easy; for examples see
http://tinyurl.com/cu9gu or http://tinyurl.com/cu9gu.

 2. Use boost::reference_wrapper. E.g.,

  int main()
  {
    typedef boost::reference_wrapper<Source> source_ref;
    Source src(0);
    boost::iostreams::stream<source_ref> s(boost::ref(src));
  }

> I was
> amazed that the code above doesn't compile. This is the error message
> reported by VC7.1:

    <snip>

> It seems that a device must be copy-constructibile.

Actually, devices can be non-copyable, since streams and stream buffers are
devices. I do mention this several places in the docs, for example, the docs
for "Source" state that input streams are sources; still, it should be much more
prominent.

There are limitations on what can be done with non-copy-constructible devices.
For example, you can't pass them to filtering_stream::push without using a
reference wrapper, except in the common case of streams and stream buffers,
which are given special treatment.

The reason for requiring devices to be copy-constructible in most cases are
described briefly here: http://tinyurl.com/7bptp. Exception safety was the main
consideration: in most contexts, the alternative to passing copies would be to
use dynamically allocated pointers, and this leads to problems for functions
which take several filters or devices as arguments.

It looks like I've never documented that the Device parameter to the class
templates stream and stream_buffer must be copy-constructible; I'll fix this.

In the example you give, which makes use of iostreams::stream's forwarding
constructors, it would be theortically possible to construct the Source
in-place, so that no copying is required. I guess it would be possible to have
the copy-constructible requirement apply only to the constructors which take a
const Source&. I must admit I've never thought of this. My guess is it will be
difficult to make it work on all the supported compilers. Because of the to
alternatives I mentioned above, I'm not sure it's worth the trouble. I'd be
happy to apply a patch, if you submit one.

> In particular, the
> code above makes at least three short-lived copies of the device.
> Question is: why? I believe this requirement is unintended and not due
> to a conscious design choice, my arguments are:
>
> 1) it's not documented, there is no mention of such requirement in
> http://www.boost.org/libs/iostreams/doc/concepts/device.html

Actually, it's documented extensively here:

  http://tinyurl.com/7bptp

;-)

> Ganesh

-- 
Jonathan Turkanis
www.kangaroologic.com

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