History of and support for std::basic_string::back()

J

JC

For as long as I could remember, basic_string never had a back() member. Ina recent discussion somewhere else, I went digging for a C++ standard and found http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf, looking for evidence that back() was indeed not standard in C++.

Yet, it's right there, in 21.4.5.10.

My questions are:

1. Has this always been the case? If so, then why are there so many STL implementations that don't seem to have back()? If not, then when was it added?

2. Most documentation references to back() say "since C++11". Is C++11 anevolution of the C++ standard, reflected in revisions to the C++ specifications? Or is there a separate, distinct "C++11" specification? If the former, where can I find the last version of C++ that wasn't considered C++11?

Thanks!
Jason
 
J

JC

On Sat, 2013-08-03, JC wrote:

...





Yes.


Thanks! Do you know when back() was introduced, and what the last C++ standard was that wasn't considered "C++11"?

Was the document I linked to the spec for what is currently being called C++11?

Thanks again,
Jason
 
J

JC

Thanks! Do you know when back() was introduced, and what the last C++ standard was that wasn't considered "C++11"?


I think what I mean is, what is the last version of the spec that was "C++98"? There is obviously a clear cut line between the two somewhere, at leastas far as gcc is concerned (not sure how meaningful that is) -- there is avery specific set of new features supported when "--std=c++0x" is specified.

Jason
 
I

Ian Collins

Please clean up the awful mess that shite google interface makes of your
quotes.

The previous one.
I think what I mean is, what is the last version of the spec that was
"C++98"?

The one published in 1998?
There is obviously a clear cut line between the two
somewhere, at least as far as gcc is concerned (not sure how
meaningful that is) -- there is a very specific set of new features
supported when "--std=c++0x" is specified.

What else would you expect?
 
J

JC

Please clean up the awful mess that shite google interface makes of your
quotes.


The previous one.


The one published in 1998?


What else would you expect?

2003 didn't exist for me either. Weird year.

I can see that this list is not what it used to be. I mistakenly thought the newsgroup was a place to get help, share information, and discuss. I didn't realize it was just an outlet for arbitrary and unwarranted angst and snark. My bad. I'll go find a C++ support group elsewhere.

Thanks for your time!
Jason
 
J

JC

The correct answers (I think) are below, for anybody that may find this post in the future and find the angry replies devoid of actual information.

For as long as I could remember, basic_string never had a back() member. In a recent discussion somewhere else, I went digging for a C++ standard and found http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf, looking for evidence that back() was indeed not standard in C++.

Yet, it's right there, in 21.4.5.10.

My questions are:

1. Has this always been the case? If so, then why are there so many STLimplementations that don't seem to have back()? If not, then when was it added?

It was added in the 2011 updates to C++.
2. Most documentation references to back() say "since C++11". Is C++11 an evolution of the C++ standard, reflected in revisions to the C++ specifications? Or is there a separate, distinct "C++11" specification?

Both. The C++ standard is ISO 14882. There was a version in 1998, then an update in 2003, then an update in 2011. The one in 2011 is a smooth evolution, but is also distinctly referred to as C++11. basic_string::back() was added in 2011.
If the former, where can I find the last version of C++ that wasn't considered C++11?

This is the 2003 version and can be found here: http://bit.ly/14PSFlb


Jason
 
J

Jorgen Grahn

On Sat, 2013-08-03, JC wrote:

...


Yes.

Thanks! Do you know when back() was introduced [...]

That was the hard part of your question, so no. Sorry.

My hidden point was: let Google (or Wikipedia) answer the easy
questions. That way you can prepare a better comp.lang.c++ question,
and be more likely to get a good answer.

/Jorgen
 
J

Jorgen Grahn

.
2003 didn't exist for me either. Weird year.

<http://en.wikipedia.org/wiki/C++#Standardization>

Year C++ Standard Informal name
------------------------------------------
1998 ISO/IEC 14882:1998 C++98
2003 ISO/IEC 14882:2003 C++03
2007 ISO/IEC TR 19768:2007 C++TR1
2011 ISO/IEC 14882:2011 C++11
I can see that this list is not what it used to be. I mistakenly
thought the newsgroup was a place to get help, share information, and
discuss. I didn't realize it was just an outlet for arbitrary and
unwarranted angst and snark.

It's both, actually. If you make an effort to write a clear
question, and if it is interesting, you'll get good replies.

The back() question was interesting, but you drowned it in standard
naming questions, and let Google Groups mess up the text itself.

/Jorgen
 
J

Jorgen Grahn

.
There have been a number of minor (mostly bugfixes and clarifications)
published by ISO/IEC, but mainly there have been four standards.

- C++89, which is the original

You mean C++98 here, of course.

/Jorgen
 
B

Bo Persson

Jorgen Grahn skrev 2013-08-03 10:13:
On Sat, 2013-08-03, JC wrote:

...

C++11 an evolution of the C++ standard, reflected in revisions to the
C++ specifications?

Yes.

Thanks! Do you know when back() was introduced [...]

That was the hard part of your question, so no. Sorry.

An ongoing problem with std::string is that it has its own section in
the standard (Clause 21) while the "real" containers are described in an
other section (Clause 23).

In the C++98 standard Clause 21 claims that basic_string has the same
interface as a reversible container (like std::vector) but if you check
the required member functions it actually doesn't. The container types
were improved and synchronized during standardization, but basic_string
wasn't always updated. Oops!

We can get some clues from this 2005 defect report:

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#534

where one user reports that it is already available on some implementations.

In C++11 it is required.


Bo Persson
 
J

JC

On Sat, 2013-08-03, JC wrote:

...


<http://en.wikipedia.org/wiki/C++#Standardization>

Year C++ Standard Informal name
------------------------------------------
1998 ISO/IEC 14882:1998 C++98
2003 ISO/IEC 14882:2003 C++03
2007 ISO/IEC TR 19768:2007 C++TR1
2011 ISO/IEC 14882:2011 C++11


It's both, actually. If you make an effort to write a clear
question, and if it is interesting, you'll get good replies.

The back() question was interesting, but you drowned it in standard
naming questions, and let Google Groups mess up the text itself.


Thanks Robert, Jorgen, Bo.

As for Google Groups, I do feel your pain. Know that I (and other Groups users who probably get the same backlash) didn't "let" it mess things up. It looks perfectly fine in their interface, so I have no possible way of fixing it. It's a Google problem not a Jason problem, but I will certainly not use it for posting later.

Thanks again guys,
Jason
 
J

James Kanze

Jorgen Grahn skrev 2013-08-03 10:13:
[...]
An ongoing problem with std::string is that it has its own section in
the standard (Clause 21) while the "real" containers are described in an
other section (Clause 23).

This is because it was around (in working drafts) long before
anyone has even heard of the STL (which provides the "real"
containers).
In the C++98 standard Clause 21 claims that basic_string has the same
interface as a reversible container (like std::vector) but if you check
the required member functions it actually doesn't. The container types
were improved and synchronized during standardization, but basic_string
wasn't always updated. Oops!

The container types were adopted from the STL, where a certain
homogeneity of interface was a major principle. Very little was
changed in the basic container types from the STL.

The standard had a string class long before STL. After the
committee voted to adopt STL, the string class was STLified.
Very incompletely, as you observe. (I know that it was still
missing `push_back` in the CD2 for C++98, for example. That one
got caught, but a number of others didn't.)

Even today, old problems have crept back in. For example, given
a non-const string, you cannot compare two characters in it
without undefined behavior; in other words:

std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...

The `if` here has undefined behavior in C++11. It also had
undefined behavior in the CD2 preceding C++98, but this
undefined behavior was spotted and (very partially) corrected.
C++11 somehow went back to the status of pre-C++98, and restored
the undefined behavior.
 
V

Vlad from Moscow

воÑкреÑенье, 4 авгуÑта 2013 г., 3:27:52 UTC+4 пользователь James Kanze напиÑал:
Jorgen Grahn skrev 2013-08-03 10:13:


[...]

An ongoing problem with std::string is that it has its own section in
the standard (Clause 21) while the "real" containers are described in an
other section (Clause 23).



This is because it was around (in working drafts) long before

anyone has even heard of the STL (which provides the "real"

containers).


In the C++98 standard Clause 21 claims that basic_string has the same
interface as a reversible container (like std::vector) but if you check
the required member functions it actually doesn't. The container types
were improved and synchronized during standardization, but basic_string
wasn't always updated. Oops!



The container types were adopted from the STL, where a certain

homogeneity of interface was a major principle. Very little was

changed in the basic container types from the STL.



The standard had a string class long before STL. After the

committee voted to adopt STL, the string class was STLified.

Very incompletely, as you observe. (I know that it was still

missing `push_back` in the CD2 for C++98, for example. That one

got caught, but a number of others didn't.)



Even today, old problems have crept back in. For example, given

a non-const string, you cannot compare two characters in it

without undefined behavior; in other words:



std::string var;

std::cin >> var;

assert( var.size() >= 2 );

if ( var[0] == var[1] )...



The `if` here has undefined behavior in C++11. It also had

undefined behavior in the CD2 preceding C++98, but this

undefined behavior was spotted and (very partially) corrected.

C++11 somehow went back to the status of pre-C++98, and restored

the undefined behavior.



Where did you see undefined behaviour in thsi code snip?

std::string var;

std::cin >> var;

assert( var.size() >= 2 );

if ( var[0] == var[1] )...
 
V

Victor Bazarov

×ÏÓËÒÅÓÅÎØÅ, 4 Á×ÇÕÓÔÁ 2013 Ç., 3:27:52 UTC+4 ÐÏÌØÚÏ×ÁÔÅÌØ James Kanze ÎÁÐÉÓÁÌ:
Jorgen Grahn skrev 2013-08-03 10:13:
[...]

Where did you see undefined behaviour in thsi code snip?

std::string var;

std::cin >> var;

assert( var.size() >= 2 );

if ( var[0] == var[1] )...

If I recall correctly, the use of 'assert' does not prevent undefined
behavior. It's a debugging tool, not a panacea.

You might want to rewrite this as

if (var.size() > 1 && var[0] == var[1]) ...

or use '.at' member which will throw 'out_of_range':

if (var.at(0) == var.at(1)) ...

V
 
B

Bart van Ingen Schenau

Even today, old problems have crept back in. For example, given a
non-const string, you cannot compare two characters in it without
undefined behavior; in other words:

std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...

The `if` here has undefined behavior in C++11. It also had undefined
behavior in the CD2 preceding C++98, but this undefined behavior was
spotted and (very partially) corrected. C++11 somehow went back to the
status of pre-C++98, and restored the undefined behavior.

If that is UB in C++11, then they caught it again.
In N3337, using the non-const operator[] on a basic_string<> does not
invalidate iterators (I am assuming that was what you were referring to).
This is stated in 21.4.1 [string.require]/6, second bullet.

Bart v Ingen Schenau
 
J

James Kanze

воÑкреÑенье, 4 авгуÑта 2013 г., 3:27:52 UTC+4 пользователь James Kanze
напиÑал:
Jorgen Grahn skrev 2013-08-03 10:13:
[...]
Even today, old problems have crept back in. For example, given
a non-const string, you cannot compare two characters in it
without undefined behavior; in other words:
std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...
The `if` here has undefined behavior in C++11. It also had
undefined behavior in the CD2 preceding C++98, but this
undefined behavior was spotted and (very partially) corrected.
C++11 somehow went back to the status of pre-C++98, and restored
the undefined behavior.
Where did you see undefined behaviour in thsi code snip?
std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...

On rereading the C++11 standard: they didn't reinject the
undefined behavior here; they banned copy on write
implementations like that of g++. (Which may be worse.)
 
J

James Kanze

Even today, old problems have crept back in. For example, given a
non-const string, you cannot compare two characters in it without
undefined behavior; in other words:
std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...
The `if` here has undefined behavior in C++11. It also had undefined
behavior in the CD2 preceding C++98, but this undefined behavior was
spotted and (very partially) corrected. C++11 somehow went back to the
status of pre-C++98, and restored the undefined behavior.
If that is UB in C++11, then they caught it again.
In N3337, using the non-const operator[] on a basic_string<> does not
invalidate iterators (I am assuming that was what you were referring to).
This is stated in 21.4.1 [string.require]/6, second bullet.

If you want to allow CoW implementations (such as the one used by g++),
then non-const operator[] (and non-const begin() and end()) must
be able to invalidate iterators, at least the first time they are
called. (And IMHO, if the standard bans CoW implementations, it is
broken.) This was recognized in previous versions of the standard.
 
Ö

Öö Tiib

James Kanze said:
Even today, old problems have crept back in. For example, given a
non-const string, you cannot compare two characters in it without
undefined behavior; in other words:
std::string var;
std::cin >> var;
assert( var.size() >= 2 );
if ( var[0] == var[1] )...
The `if` here has undefined behavior in C++11. It also had
undefined behavior in the CD2 preceding C++98, but this undefined
behavior was spotted and (very partially) corrected. C++11 somehow
went back to the status of pre-C++98, and restored the undefined
behavior.
If that is UB in C++11, then they caught it again.
In N3337, using the non-const operator[] on a basic_string<> does not
invalidate iterators (I am assuming that was what you were referring
to). This is stated in 21.4.1 [string.require]/6, second bullet.

If you want to allow CoW implementations (such as the one used by
g++), then non-const operator[] (and non-const begin() and end()) must
be able to invalidate iterators, at least the first time they are
called. (And IMHO, if the standard bans CoW implementations, it is
broken.) This was recognized in previous versions of the standard.

CoW requires multi-threaded synchronization deep in the inners of
std::string, where it would be totally on the wrong level.

That is lock-less synchronization so it is fine to hide it.
In this regard, CoW seems like a typical premature optimization attempt
which may easily become a pessimization on new hardware (thinking NUMA),
so why are you so keen about supporting it?

There are other optimizations like short string optimization or support to
string literals about what one can say exactly the same thing. All the
optimizations are good for certain usage pattern and bad for other
usage pattern. That makes those good candidates to be optional (like
checked iterators are). If standard specially forbids something that can be
very useful then that is surprising for C++. C++ has such endless pile of
very questionable features but these may be useful for 0.2% of developers
once during their whole career so those stay in.
If banning CoW conincidentally eliminates obscure UB in things like var
[0]==var[1], then I'm all for it.

That UB can be corrected by several other means. YMMV but better remove
(or constify) operator[] and better both to string and map. Endless
nuisance with those.
 
Ö

Öö Tiib

As far as I have understood this is not really the case unfortunately.
Lock-less synchronization might be better than locks, but they still have
to use proper memory barriers, to avoid code reordering by hardware. Memory
barriers may become quite expensive, especially on NUMA.

How that matters? It can't deadlock so it can be hidden from developer. Let
me try again?

std::string is part of standard library. When it is ridiculously expensive
to internally CoW on platform then standard library implementation for
that platform does never CoW. When it is ridiculously cheap to CoW then
standard library implementation for that platform does always CoW. When it
is dim, then there can be compiler options. So the issue *is* solved on
correct level.

Now when CoW is forbidden even on cases when it is most efficient then
developers are encouraged to deal with it. They will. For example they
port CString of Microsoft ATL and use it instead of using std::string.
Or something else like that for single threaded embedded platform. Then
standard is broken like James said because ... come on ... it is
platform-specific optimization of string of characters. Such mundane
things should not be concern of programmers to care.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top