Topic: N2284 defect: basic_string incompletely move-aware?


Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Tue, 3 Jul 2007 13:02:06 GMT
Raw View
Daniel Kr=C3=BCgler skrev:
> The synopsis of basic_string [basic.string] reveals that some relevant
> members are not move-aware, also
> they should, IMO: The following lists presents those members, which
> only provide an overload with
> const basic_string&:
>=20
> - basic_string& operator+=3D(const basic_string& str );
> - basic_string& append(const basic_string& str );
> - basic_string& insert(size_type pos1 , const basic_string& str );
> - basic_string& replace(size_type pos1 , size_type n1, const
> basic_string& str );
> - basic_string& replace(iterator i1 , iterator i2 , const
> basic_string& str );

Isn't the speed-up limited to the case where the string is empty
or the string to replace is the whole string?

-Thorsten

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?iso-8859-1?q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Tue, 3 Jul 2007 08:06:45 CST
Raw View
On 1 Jul., 17:22, Chris Jefferson <4zuma...@gmail.com> wrote:
> I believe the reason these don't have a move-aware copy is that it is
> not obvious how they could be made use of. The general opinion
> nowadays seems to be that strings should be composed of a single
> backing string.

You are right. About 2 days ago I tried to send my own correction
to this NAD, because I recognized the same thing, unfortunatly this
answer did not came into this group up to now.

My logical error was, that I compared += of basic_string with
push_back
of a container with the tiny but important difference, that += of
basic_string
accepts a basic_string and the container<T> accepts a T....

> I suppose someone could make a lazy string which was a list of blocks
> of memory which were all composed into one the first time a member was
> called which can read the contents of the string. A "compose on
> write", rather than "copy on write" :) It would have the same problems
> copy on write strings have, which is that they can be tricky in
> threads.

Right.

> I can't see why not to add them, even if no-one ever uses them, as the
> C++ standard tends to aim to allow multiple implementations.

I agree that this is possible (harmless), but could easily lead to an
overload explosion, because I could similarily argue that one should
add moveable overloads for every function currently taking a
reference to const basic_string<...>.

Thanks for your answer,

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?iso-8859-1?q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Tue, 3 Jul 2007 08:03:05 CST
Raw View
On 28 Jun., 01:17, Daniel Kr   gler <daniel.krueg...@googlemail.com>
wrote:
> The synopsis of basic_string [basic.string] reveals that some relevant
> members are not move-aware, also they should, IMO.

I reconsidered the current state of affairs and understand, that my
above given reasoning is not convincing. A move-supporting
basic_string& operator+=(const basic_string& str );
does not have more or less advantages than

bool operator==(const basic_string&, const basic_string& );

versus

bool operator==(basic_string&&, basic_string&& );

My false idea was that I compared

std::vector<T>::push_back()

(which expects a complete T instance) with

basic_string& operator+=(basic_string&& str );

which could not really *move* its argument.

Sorry for the noise,

Daniel Kr   gler



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jgottman@carolina.rr.com (Joe Gottman)
Date: Wed, 4 Jul 2007 03:50:42 GMT
Raw View
Daniel Kr=FCgler wrote:
> On 28 Jun., 01:17, Daniel Kr=FCgler <daniel.krueg...@googlemail.com>
> wrote:
>> The synopsis of basic_string [basic.string] reveals that some relevant
>> members are not move-aware, also they should, IMO.
>=20
> I reconsidered the current state of affairs and understand, that my
> above given reasoning is not convincing. A move-supporting
> basic_string& operator+=3D(const basic_string& str );
> does not have more or less advantages than
>=20
> bool operator=3D=3D(const basic_string&, const basic_string& );
>=20
> versus
>=20
> bool operator=3D=3D(basic_string&&, basic_string&& );
>=20
> My false idea was that I compared
>=20
> std::vector<T>::push_back()
>=20
> (which expects a complete T instance) with
>=20
> basic_string& operator+=3D(basic_string&& str );
>=20
> which could not really *move* its argument.
>=20
> Sorry for the noise,
>=20
>
    I don't understand this. The reason for making=20
basic_string::operator+() move-aware is to avoid unnecessary=20
reallocation.   So what's wrong with using the following algorithm in=20
operator+=3D ?

basic_string & operator+=3D(basic_string &&str)
{
     size_t total_size =3D size() + str.size();
     if (total_size <=3D capacity()) {
 // insert str at the end of *this.  No reallocation necessary
     } else if (total_size <=3D str.capacity()) {
 // insert *this at the beginning of str.  No reallocation necessary
 swap(str);
     } else {
 //We have to reallocate.  Do so
     }
     return *this;
}

Joe Gottman

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Wed, 4 Jul 2007 17:29:16 CST
Raw View
In article <468adb5c$0$15013$4c368faf@roadrunner.com>,
 jgottman@carolina.rr.com (Joe Gottman) wrote:

> Daniel Kr   gler wrote:
> > On 28 Jun., 01:17, Daniel Kr   gler <daniel.krueg...@googlemail.com>
> > wrote:
> >> The synopsis of basic_string [basic.string] reveals that some relevant
> >> members are not move-aware, also they should, IMO.
> >
> > I reconsidered the current state of affairs and understand, that my
> > above given reasoning is not convincing. A move-supporting
> > basic_string& operator+=(const basic_string& str );
> > does not have more or less advantages than
> >
> > bool operator==(const basic_string&, const basic_string& );
> >
> > versus
> >
> > bool operator==(basic_string&&, basic_string&& );
> >
> > My false idea was that I compared
> >
> > std::vector<T>::push_back()
> >
> > (which expects a complete T instance) with
> >
> > basic_string& operator+=(basic_string&& str );
> >
> > which could not really *move* its argument.
> >
> > Sorry for the noise,
> >
> >
>     I don't understand this. The reason for making
> basic_string::operator+() move-aware is to avoid unnecessary
> reallocation.   So what's wrong with using the following algorithm in
> operator+= ?
>
> basic_string & operator+=(basic_string &&str)
> {
>      size_t total_size = size() + str.size();
>      if (total_size <= capacity()) {
>  // insert str at the end of *this.  No reallocation necessary
>      } else if (total_size <= str.capacity()) {
>  // insert *this at the beginning of str.  No reallocation necessary
>  swap(str);
>      } else {
>  //We have to reallocate.  Do so
>      }
>      return *this;
> }

That's a good point.  I'm wondering if 17.4.4.4 [lib.member.functions]
already gives us this latitude:

2- An implementation can declare additional non-virtual member function
signatures within a class:

.

*  by adding a member function signature for a member function name.

3- A call to a member function signature described in the C++ Standard
library behaves the same as if the implementation declares no additional
member function signatures.

-Howard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?iso-8859-1?q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Fri, 6 Jul 2007 09:24:08 CST
Raw View
On Jul 4, 5:50 am, jgott...@carolina.rr.com (Joe Gottman) wrote:
>     I don't understand this. The reason for making
> basic_string::operator+() move-aware is to avoid unnecessary
> reallocation.   So what's wrong with using the following algorithm in
> operator+= ?

I confess that my very first reaction might have been somewhat
extreme, after realizing that the actual request was initiated due
to an error in reasoning.

I agree that move-overloads of these (and possibly some others)
mutable operations might make more sense (at least for a given
percentage of cases, not 100% as for the e.g. MoveConstruction)
than those for purely immutable operations as operator==.

Thanks for this reminder,

Daniel

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?iso-8859-1?q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Wed, 27 Jun 2007 17:17:30 CST
Raw View
The synopsis of basic_string [basic.string] reveals that some relevant
members are not move-aware, also
they should, IMO: The following lists presents those members, which
only provide an overload with
const basic_string&:

- basic_string& operator+=(const basic_string& str );
- basic_string& append(const basic_string& str );
- basic_string& insert(size_type pos1 , const basic_string& str );
- basic_string& replace(size_type pos1 , size_type n1, const
basic_string& str );
- basic_string& replace(iterator i1 , iterator i2 , const
basic_string& str );

Proposed resolution:

Add the following class members to the basic_string synopsis in
[basic.string] and to the corresponding
detailed section [string::op+=], [string::append], [string::insert],
and [string::replace]:

 basic_string& operator+=(basic_string&& str );
 basic_string& append(basic_string&& str );
 basic_string& insert(size_type pos1 , basic_string&& str );
 basic_string& replace(size_type pos1 , size_type n1, basic_string&&
str );
 basic_string& replace(iterator i1 , iterator i2 , basic_string&&
str );

Greetings from Bremen,

Daniel Kr   gler


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Chris Jefferson <4zumanga@gmail.com>
Date: Sun, 1 Jul 2007 09:22:56 CST
Raw View
On Jun 28, 12:17 am, Daniel Kr   gler <daniel.krueg...@googlemail.com>
wrote:
> The synopsis of basic_string [basic.string] reveals that some relevant
> members are not move-aware, also
> they should, IMO: The following lists presents those members, which
> only provide an overload with
> const basic_string&:

I believe the reason these don't have a move-aware copy is that it is
not obvious how they could be made use of. The general opinion
nowadays seems to be that strings should be composed of a single
backing string.

I suppose someone could make a lazy string which was a list of blocks
of memory which were all composed into one the first time a member was
called which can read the contents of the string. A "compose on
write", rather than "copy on write" :) It would have the same problems
copy on write strings have, which is that they can be tricky in
threads.

I can't see why not to add them, even if no-one ever uses them, as the
C++ standard tends to aim to allow multiple implementations.

> - basic_string& operator+=(const basic_string& str );
> - basic_string& append(const basic_string& str );
> - basic_string& insert(size_type pos1 , const basic_string& str );
> - basic_string& replace(size_type pos1 , size_type n1, const
> basic_string& str );
> - basic_string& replace(iterator i1 , iterator i2 , const
> basic_string& str );
>
> Proposed resolution:
>
> Add the following class members to the basic_string synopsis in
> [basic.string] and to the corresponding
> detailed section [string::op+=], [string::append], [string::insert],
> and [string::replace]:
>
>  basic_string& operator+=(basic_string&& str );
>  basic_string& append(basic_string&& str );
>  basic_string& insert(size_type pos1 , basic_string&& str );
>  basic_string& replace(size_type pos1 , size_type n1, basic_string&&
> str );
>  basic_string& replace(iterator i1 , iterator i2 , basic_string&&
> str );
>
> Greetings from Bremen,
>
> Daniel Kr   gler
>


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Mathias Gaunard <loufoque@gmail.com>
Date: Mon, 2 Jul 2007 23:14:27 CST
Raw View
On Jun 28, 1:17 am, Daniel Kr   gler <daniel.krueg...@googlemail.com>
wrote:
> The synopsis of basic_string [basic.string] reveals that some relevant
> members are not move-aware, also
> they should, IMO: The following lists presents those members, which
> only provide an overload with
> const basic_string&:
>
> - basic_string& operator+=(const basic_string& str );
> - basic_string& append(const basic_string& str );
> - basic_string& insert(size_type pos1 , const basic_string& str );
> - basic_string& replace(size_type pos1 , size_type n1, const
> basic_string& str );
> - basic_string& replace(iterator i1 , iterator i2 , const
> basic_string& str );

I fail to see how copying the string can be avoided in the general
case for those functions.



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]