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:
parent
d6476f90da
commit
c6d4257972
3 changed files with 305 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
|
|
244
libstdc++-v3/testsuite/backward/strstream_move.cc
Normal file
244
libstdc++-v3/testsuite/backward/strstream_move.cc
Normal 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();
|
||||
}
|
Loading…
Add table
Reference in a new issue