mirror of git://gcc.gnu.org/git/gcc.git
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
|
|
@ -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>
|
2018-05-01 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
|
||||||
|
|
||||||
PR libstdc++/84654
|
PR libstdc++/84654
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
virtual ~strstreambuf();
|
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:
|
public:
|
||||||
void freeze(bool = true) throw ();
|
void freeze(bool = true) throw ();
|
||||||
char* str() throw ();
|
char* str() throw ();
|
||||||
|
|
@ -98,10 +125,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
= ios_base::in | ios_base::out);
|
= ios_base::in | ios_base::out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if __cplusplus < 201103L
|
||||||
strstreambuf&
|
strstreambuf&
|
||||||
operator=(const strstreambuf&);
|
operator=(const strstreambuf&);
|
||||||
|
|
||||||
strstreambuf(const strstreambuf&);
|
strstreambuf(const strstreambuf&);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Dynamic allocation, possibly using _M_alloc_fun and _M_free_fun.
|
// Dynamic allocation, possibly using _M_alloc_fun and _M_free_fun.
|
||||||
char* _M_alloc(size_t);
|
char* _M_alloc(size_t);
|
||||||
|
|
@ -110,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
// Helper function used in constructors.
|
// Helper function used in constructors.
|
||||||
void _M_setup(char* __get, char* __put, streamsize __n) throw ();
|
void _M_setup(char* __get, char* __put, streamsize __n) throw ();
|
||||||
|
|
||||||
private:
|
|
||||||
// Data members.
|
// Data members.
|
||||||
void* (*_M_alloc_fun)(size_t);
|
void* (*_M_alloc_fun)(size_t);
|
||||||
void (*_M_free_fun)(void*);
|
void (*_M_free_fun)(void*);
|
||||||
|
|
@ -130,6 +158,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
istrstream(const char*, streamsize);
|
istrstream(const char*, streamsize);
|
||||||
virtual ~istrstream();
|
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 ();
|
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
|
||||||
char* str() throw ();
|
char* str() throw ();
|
||||||
|
|
||||||
|
|
@ -145,6 +181,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
ostrstream(char*, int, ios_base::openmode = ios_base::out);
|
ostrstream(char*, int, ios_base::openmode = ios_base::out);
|
||||||
virtual ~ostrstream();
|
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 ();
|
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
|
||||||
void freeze(bool = true) throw();
|
void freeze(bool = true) throw();
|
||||||
char* str() throw ();
|
char* str() throw ();
|
||||||
|
|
@ -167,6 +211,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
strstream(char*, int, ios_base::openmode = ios_base::in | ios_base::out);
|
strstream(char*, int, ios_base::openmode = ios_base::in | ios_base::out);
|
||||||
virtual ~strstream();
|
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 ();
|
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
|
||||||
void freeze(bool = true) throw ();
|
void freeze(bool = true) throw ();
|
||||||
_GLIBCXX_PURE int pcount() const throw ();
|
_GLIBCXX_PURE int pcount() const throw ();
|
||||||
|
|
|
||||||
|
|
@ -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…
Reference in New Issue