basic_streambuf
copy-constructible?Section: 31.6.3.2 [streambuf.cons] Status: NAD Submitter: Martin Sebor Opened: 2003-09-18 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [streambuf.cons].
View all issues with NAD status.
Discussion:
The reflector thread starting with c++std-lib-11346 notes that the class
template basic_streambuf
, along with basic_stringbuf
and basic_filebuf
,
is copy-constructible but that the semantics of the copy constructors
are not defined anywhere. Further, different implementations behave
differently in this respect: some prevent copy construction of objects
of these types by declaring their copy ctors and assignment operators
private, others exhibit undefined behavior, while others still give
these operations well-defined semantics.
Note that this problem doesn't seem to be isolated to just the three types mentioned above. A number of other types in the library section of the standard provide a compiler-generated copy ctor and assignment operator yet fail to specify their semantics. It's believed that the only types for which this is actually a problem (i.e. types where the compiler-generated default may be inappropriate and may not have been intended) are locale facets. See issue 439.
[ 2009-07 Frankfurt ]
NAD. Option B is already in the Working Draft.
Proposed resolution:
27.5.2 [lib.streambuf]: Add into the synopsis, public section, just above the destructor declaration:
basic_streambuf(const basic_streambuf& sb); basic_streambuf& operator=(const basic_streambuf& sb);
Insert after 27.5.2.1, paragraph 2:
basic_streambuf(const basic_streambuf& sb);Constructs a copy of
sb
.Postcondtions:
eback() == sb.eback() gptr() == sb.gptr() egptr() == sb.egptr() pbase() == sb.pbase() pptr() == sb.pptr() epptr() == sb.epptr() getloc() == sb.getloc()basic_streambuf& operator=(const basic_streambuf& sb);Assigns the data members of
sb
to this.Postcondtions:
eback() == sb.eback() gptr() == sb.gptr() egptr() == sb.egptr() pbase() == sb.pbase() pptr() == sb.pptr() epptr() == sb.epptr() getloc() == sb.getloc()Returns: *this.
27.7.1 [lib.stringbuf]:
Option A:
Insert into the
basic_stringbuf
synopsis in the private section:basic_stringbuf(const basic_stringbuf&); // not defined basic_stringbuf& operator=(const basic_stringbuf&); // not defined
Option B:
Insert into the
basic_stringbuf
synopsis in the public section:basic_stringbuf(const basic_stringbuf& sb); basic_stringbuf& operator=(const basic_stringbuf& sb);27.7.1.1, insert after paragraph 4:
basic_stringbuf(const basic_stringbuf& sb);Constructs an independent copy of
sb
as if withsb.str()
, and with the openmode thatsb
was constructed with.Postcondtions:
str() == sb.str() gptr() - eback() == sb.gptr() - sb.eback() egptr() - eback() == sb.egptr() - sb.eback() pptr() - pbase() == sb.pptr() - sb.pbase() getloc() == sb.getloc()Note: The only requirement on
epptr()
is that it point beyond the initialized range if an output sequence exists. There is no requirement thatepptr() - pbase() == sb.epptr() - sb.pbase()
.basic_stringbuf& operator=(const basic_stringbuf& sb);After assignment the
basic_stringbuf
has the same state as if it were initially copy constructed fromsb
, except that thebasic_stringbuf
is allowed to retain any excess capacity it might have, which may in turn effect the value ofepptr()
.
27.8.1.1 [lib.filebuf]
Insert at the bottom of the basic_filebuf
synopsis:
private: basic_filebuf(const basic_filebuf&); // not defined basic_filebuf& operator=(const basic_filebuf&); // not defined
[Kona: this is an issue for basic_streambuf
itself and for its
derived classes. We are leaning toward allowing basic_streambuf
to
be copyable, and specifying its precise semantics. (Probably the
obvious: copying the buffer pointers.) We are less sure whether
the streambuf
derived classes should be copyable. Howard will
write up a proposal.]
[Sydney: Dietmar presented a new argument against basic_streambuf
being copyable: it can lead to an encapsulation violation. filebuf
inherits from streambuf
. Now suppose you inherit a my_hijacking_buf
from streambuf
. You can copy the streambuf
portion of a filebuf
to a
my_hijacking_buf
, giving you access to the pointers into the
filebuf
's internal buffer. Perhaps not a very strong argument, but
it was strong enough to make people nervous. There was weak
preference for having streambuf
not be copyable. There was weak
preference for having stringbuf
not be copyable even if streambuf
is. Move this issue to open for now.
]
[
2007-01-12, Howard:
Rvalue Reference Recommendations for Chapter 27
recommends protected copy constructor and assignment for basic_streambuf
with the same semantics
as would be generated by the compiler. These members aid in derived classes implementing move semantics.
A protected copy constructor and copy assignment operator do not expose encapsulation more so than it is
today as each data member of a basic_streambuf
is already both readable and writable by derived
classes via various get/set protected member functions (eback()
, setp()
, etc.). Rather
a protected copy constructor and copy assignment operator simply make the job of derived classes implementing
move semantics less tedious and error prone.
]
Rationale:
27.5.2 [lib.streambuf]: The proposed basic_streambuf
copy constructor
and assignment operator are the same as currently implied by the lack
of declarations: public and simply copies the data members. This
resolution is not a change but a clarification of the current
standard.
27.7.1 [lib.stringbuf]: There are two reasonable options: A) Make
basic_stringbuf
not copyable. This is likely the status-quo of
current implementations. B) Reasonable copy semantics of
basic_stringbuf
can be defined and implemented. A copyable
basic_streambuf
is arguably more useful than a non-copyable one. This
should be considered as new functionality and not the fixing of a
defect. If option B is chosen, ramifications from issue 432 are taken
into account.
27.8.1.1 [lib.filebuf]: There are no reasonable copy semantics for
basic_filebuf
.