Issue 421: is basic_streambuf copy-constructible? (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
421. is 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(i).
[ 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
sbto 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_stringbufsynopsis 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_stringbufsynopsis 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
sbas if withsb.str(), and with the openmode thatsbwas 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_stringbufhas the same state as if it were initially copy constructed fromsb, except that thebasic_stringbufis 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 basicstreambuf itself and for its derived classes. We are leaning toward allowing basicstreambuf 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 basicstreambuf being copyable: it can lead to an encapsulation violation. filebuf inherits from streambuf. Now suppose you inherit a myhijackingbuf from streambuf. You can copy the streambuf portion of a filebuf to amyhijackingbuf, giving you access to the pointers into thefilebuf'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 27recommends protected copy constructor and assignment for basicstreambuf 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 basicstreambuf 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) Makebasic_stringbuf not copyable. This is likely the status-quo of current implementations. B) Reasonable copy semantics ofbasic_stringbuf can be defined and implemented. A copyablebasic_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 forbasic_filebuf.