PR libstdc++/69608 Move semantics for strstreambuf

In libstdc++ the deprecated char* streams are non-copyable, as was
required pre-C++11.

Since C++11 the standard implies that those streams should be copyable,
but doesn't specify the effects of copying them. This is surely a
defect, so for consistency with other implementations this change makes
them movable, but not copyable.

	PR libstdc++/69608
	* include/backward/strstream (strstreambuf): Define move constructor
	and move assignment operator.
	(istrstream, ostrstream, strstream): Likewise.
	* testsuite/backward/strstream_move.cc: New.

From-SVN: r259842
This commit is contained in:
Jonathan Wakely 2018-05-02 17:25:44 +01:00 committed by Jonathan Wakely
parent d6476f90da
commit c6d4257972
3 changed files with 305 additions and 1 deletions

View File

@ -1,3 +1,11 @@
2018-05-02 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/69608
* include/backward/strstream (strstreambuf): Define move constructor
and move assignment operator.
(istrstream, ostrstream, strstream): Likewise.
* testsuite/backward/strstream_move.cc: New.
2018-05-01 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
PR libstdc++/84654

View File

@ -81,6 +81,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual ~strstreambuf();
#if __cplusplus >= 201103L
strstreambuf(strstreambuf&& __rhs) noexcept
: _Base(__rhs), _M_alloc_fun(__rhs._M_alloc_fun),
_M_free_fun(__rhs._M_free_fun), _M_dynamic(__rhs._M_dynamic),
_M_frozen(__rhs._M_frozen), _M_constant(__rhs._M_constant)
{
__rhs.setg(nullptr, nullptr, nullptr);
__rhs.setp(nullptr, nullptr);
}
strstreambuf&
operator=(strstreambuf&& __rhs) noexcept
{
if (_M_dynamic && !_M_frozen)
_M_free(eback());
_Base::operator=(static_cast<const _Base&>(__rhs));
_M_alloc_fun = __rhs._M_alloc_fun;
_M_free_fun = __rhs._M_free_fun;
_M_dynamic = __rhs._M_dynamic;
_M_frozen = __rhs._M_frozen;
_M_constant = __rhs._M_constant;
__rhs.setg(nullptr, nullptr, nullptr);
__rhs.setp(nullptr, nullptr);
return *this;
}
#endif
public:
void freeze(bool = true) throw ();
char* str() throw ();
@ -98,10 +125,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
= ios_base::in | ios_base::out);
private:
#if __cplusplus < 201103L
strstreambuf&
operator=(const strstreambuf&);
strstreambuf(const strstreambuf&);
#endif
// Dynamic allocation, possibly using _M_alloc_fun and _M_free_fun.
char* _M_alloc(size_t);
@ -110,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Helper function used in constructors.
void _M_setup(char* __get, char* __put, streamsize __n) throw ();
private:
// Data members.
void* (*_M_alloc_fun)(size_t);
void (*_M_free_fun)(void*);
@ -130,6 +158,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
istrstream(const char*, streamsize);
virtual ~istrstream();
#if __cplusplus >= 201103L
istrstream(istrstream&& __rhs)
: istream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
{ set_rdbuf(&_M_buf); }
istrstream& operator=(istrstream&&) = default;
#endif
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
char* str() throw ();
@ -145,6 +181,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
ostrstream(char*, int, ios_base::openmode = ios_base::out);
virtual ~ostrstream();
#if __cplusplus >= 201103L
ostrstream(ostrstream&& __rhs)
: ostream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
{ set_rdbuf(&_M_buf); }
ostrstream& operator=(ostrstream&&) = default;
#endif
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
void freeze(bool = true) throw();
char* str() throw ();
@ -167,6 +211,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
strstream(char*, int, ios_base::openmode = ios_base::in | ios_base::out);
virtual ~strstream();
#if __cplusplus >= 201103L
strstream(strstream&& __rhs)
: iostream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
{ set_rdbuf(&_M_buf); }
strstream& operator=(strstream&&) = default;
#endif
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
void freeze(bool = true) throw ();
_GLIBCXX_PURE int pcount() const throw ();

View File

@ -0,0 +1,244 @@
// Copyright (C) 2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-Wno-deprecated" }
// { dg-do run { target c++11 } }
#include <strstream>
#include <testsuite_hooks.h>
void
test01()
{
std::istrstream is("15 16");
std::istrstream is2 = std::move(is);
int a;
is >> a;
VERIFY( !is );
is2 >> a;
VERIFY( is2 );
VERIFY( a == 15 );
std::istrstream is3 = std::move(is2);
int b;
is2 >> b;
VERIFY( !is2 );
is3 >> b;
VERIFY( is3 );
VERIFY( b == 16 );
}
void
test02()
{
std::istrstream is("");
int a;
is >> a;
VERIFY( !is );
is = std::istrstream("17 18");
is >> a;
VERIFY( is );
VERIFY( a == 17 );
is = std::istrstream("");
int b;
is >> b;
VERIFY( !is );
}
void
test03()
{
std::ostrstream os;
os << "a few chars"; // fits in initial allocation
char* s = os.str(); // os now frozen
std::ostrstream os2 = std::move(os);
VERIFY( os2.str() == s );
VERIFY( os.str() == nullptr );
os2.freeze(false);
os2 << "enough additional chars to force a reallocation";
VERIFY( os2 );
s = os2.str(); // os2 now frozen
std::ostrstream os3 = std::move(os2);
VERIFY( os3.str() == s );
VERIFY( os2.str() == nullptr );
delete[] s;
}
void
test04()
{
char buf[16];
std::ostrstream os(buf, sizeof(buf));
os << "a few chars";
char* s = os.str(); // os now frozen
VERIFY( s == buf );
std::ostrstream os2 = std::move(os);
VERIFY( os2.str() == s );
VERIFY( os.str() == nullptr );
os2.freeze(false);
os2 << "enough additional chars to force a reallocation";
VERIFY( !os2 );
s = os2.str(); // os2 now frozen
VERIFY( s == buf );
std::ostrstream os3 = std::move(os2);
VERIFY( os3.str() == s );
VERIFY( os2.str() == nullptr );
}
void
test05()
{
char buf[] = "0123456789";
std::ostrstream os(buf, 1);
os << "aa";
VERIFY( !os );
os = std::ostrstream(buf, 10);
os << "some chars";
VERIFY( os );
VERIFY( os.pcount() == 10 );
os << "a";
VERIFY( !os );
os = std::ostrstream();
os << "a";
VERIFY( os );
VERIFY( os.pcount() == 1 );
char* s = os.str(); // os now frozen
os = std::ostrstream();
os.freeze(false); // no effect
delete[] s;
}
void
test06()
{
char buf[] = "15 16";
std::strstream ss(buf, 5, std::ios::in|std::ios::app);
std::strstream ss2 = std::move(ss);
int a;
ss >> a;
VERIFY( !ss );
ss2 >> a;
VERIFY( ss2 );
VERIFY( a == 15 );
std::strstream ss3 = std::move(ss2);
int b;
ss2 >> b;
VERIFY( !ss2 );
ss3 >> b;
VERIFY( ss3 );
VERIFY( b == 16 );
}
void
test07()
{
std::strstream ss;
int a;
ss >> a;
VERIFY( !ss );
char buf[] = "17 18";
ss = std::strstream(buf, 5, std::ios::in|std::ios::app);
ss >> a;
VERIFY( ss );
VERIFY( a == 17 );
ss = std::strstream();
int b;
ss >> b;
VERIFY( !ss );
}
void
test08()
{
std::strstream ss;
ss << "a few chars"; // fits in initial allocation
char* s = ss.str(); // ss now frozen
std::strstream ss2 = std::move(ss);
VERIFY( ss2.str() == s );
VERIFY( ss.str() == nullptr );
ss2.freeze(false);
ss2 << "enough additional chars to force a reallocation";
VERIFY( ss2 );
s = ss2.str(); // ss2 now frozen
std::strstream ss3 = std::move(ss2);
VERIFY( ss3.str() == s );
VERIFY( ss2.str() == nullptr );
delete[] s;
}
void
test09()
{
char buf[16];
std::strstream ss(buf, sizeof(buf));
ss << "a few chars";
char* s = ss.str(); // ss now frozen
VERIFY( s == buf );
std::strstream ss2 = std::move(ss);
VERIFY( ss2.str() == s );
VERIFY( ss.str() == nullptr );
ss2.freeze(false);
ss2 << "enough additional chars to force a reallocation";
VERIFY( !ss2 );
s = ss2.str(); // ss2 now frozen
VERIFY( s == buf );
std::strstream ss3 = std::move(ss2);
VERIFY( ss3.str() == s );
VERIFY( ss2.str() == nullptr );
}
void
test10()
{
char buf[] = "0123456789";
std::strstream ss(buf, 1);
ss << "aa";
VERIFY( !ss );
ss = std::strstream(buf, 10);
ss << "some chars";
VERIFY( ss );
VERIFY( ss.pcount() == 10 );
ss << "a";
VERIFY( !ss );
ss = std::strstream();
ss << "a";
VERIFY( ss );
VERIFY( ss.pcount() == 1 );
char* s = ss.str(); // ss now frozen
ss = std::strstream();
ss.freeze(false); // no effect
delete[] s;
}
int
main()
{
test01();
test02();
test03();
test04();
test05();
test05();
test06();
test07();
test08();
test09();
test10();
}