Rationale for 21.3.4p1

O

Old Wolf

It was brought to my attention today that the Standard
(1998 version, anyway) says that if s is a const
std::string, then:
s[s.size()]

is well-defined and evaluates to 0.

Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
 
A

Alf P. Steinbach

* Old Wolf:
It was brought to my attention today that the Standard
(1998 version, anyway) says that if s is a const
std::string, then:
s[s.size()]

is well-defined and evaluates to 0.

Does it?

Wouldn't /really/ surprise me but I'm unfamiliar with that requirement.

Offhand, I'd think it was Undefined Behavior.


Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.

In practice all implementations use one contiguous buffer which is also
the result of c_str().

Cheers, & hth.,

- Alf
 
D

Dave Rahardja

Old Wolf said:
It was brought to my attention today that the Standard
(1998 version, anyway) says that if s is a const
std::string, then:
s[s.size()]

is well-defined and evaluates to 0.

Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.

I hazard it's because that behavior makes std::string behave more or
less like a C string, and lets you iterate through the string, exiting
when operator[] returns 0.

-dr
 
P

peter koch

Old Wolf said:
It was brought to my attention today that the Standard
(1998 version, anyway) says that if s is a const
std::string, then:
s[s.size()]
is well-defined and evaluates to 0.
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.

I hazard it's because that behavior makes std::string behave more or
less like a C string, and lets you iterate through the string, exiting
when operator[] returns 0.
That can't be the reason as this requirement is for const std::string
only.
I reckon it has to do with some legacy support from before
standardization, but it is only a guess.
A good question from the old wolf!

/Peter
 
O

Old Wolf

Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.

In practice all implementations use one contiguous buffer which is also
the result of c_str().

Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.
 
A

Alf P. Steinbach

* Old Wolf:
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
In practice all implementations use one contiguous buffer which is also
the result of c_str().

Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.

For a const string?

Well, it's not a convincing argument, just an idea as to rationale.

Cheers,

- Alf
 
K

Kai-Uwe Bux

Alf said:
* Old Wolf:
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
In practice all implementations use one contiguous buffer which is also
the result of c_str().

Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.

For a const string?

Well, it's not a convincing argument, just an idea as to rationale.

Keep in mind that non-const strings also have a const-member operator[] that
gets called when the string is referred to as const, e.g., passed to a
function that takes a const string & parameter. The standard requires that
operator[]( size() ) returns 0 in those cases.


Best

Kai-Uwe Bux
 
J

James Kanze

Alf said:
* Old Wolf:
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
In practice all implementations use one contiguous buffer which is also
the result of c_str().
Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.
For a const string?
Well, it's not a convincing argument, just an idea as to rationale.
Keep in mind that non-const strings also have a const-member
operator[] that gets called when the string is referred to as
const, e.g., passed to a function that takes a const string &
parameter. The standard requires that operator[]( size() )
returns 0 in those cases.

I'm not sure how this interacts with the upcoming requirement
that the data in a string be contiguous, but at least at
present, the implementation of the const operator[] could be
something like:

CharT const&
basic_string< ... >::eek:perator[]( size_t i ) const
{
static CharT const nul( 0 ) ;
return i < size() ? myRep[ i ] : nul ;
}
 
D

Daniel T.

James Kanze said:
Alf said:
* Old Wolf:
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
In practice all implementations use one contiguous buffer which is also
the result of c_str().
Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.
For a const string?
Well, it's not a convincing argument, just an idea as to rationale.
Keep in mind that non-const strings also have a const-member
operator[] that gets called when the string is referred to as
const, e.g., passed to a function that takes a const string &
parameter. The standard requires that operator[]( size() )
returns 0 in those cases.

I'm not sure how this interacts with the upcoming requirement
that the data in a string be contiguous, but at least at
present, the implementation of the const operator[] could be
something like:

CharT const&
basic_string< ... >::eek:perator[]( size_t i ) const
{
static CharT const nul( 0 ) ;
return i < size() ? myRep[ i ] : nul ;
}

Is string's iterator required to behave the same way?

void foo( const string& s ) {
string::const_iterator it = s.begin();
string::value_type c = it[s.size()]; // well defined?
}
 
P

Pete Becker

* Old Wolf:
It was brought to my attention today that the Standard
(1998 version, anyway) says that if s is a const
std::string, then:
s[s.size()]

is well-defined and evaluates to 0.

Does it?

Wouldn't /really/ surprise me but I'm unfamiliar with that requirement.

It's not hard to find. [string.access]/1.
 
J

James Kanze

James Kanze said:
Alf P. Steinbach wrote:
* Old Wolf:
Why is this? It seems to me that it places undue
constraint on the implementation. I have looked at
implementations in the past that just maintain a
counted string, and only append the \0 to the
buffer when c_str() is called. Such an implementation
would have to include overhead in its operator[] function
that would not be necessary without this clause.
In practice all implementations use one contiguous
buffer which is also the result of c_str().
Yes; but implementations need not actually put the 0 at
the end of the buffer until it's required, they could
behave just like every other library's counted string
in the meantime.
For a const string?
Well, it's not a convincing argument, just an idea as to
rationale.
Keep in mind that non-const strings also have a const-member
operator[] that gets called when the string is referred to as
const, e.g., passed to a function that takes a const string &
parameter. The standard requires that operator[]( size() )
returns 0 in those cases.
I'm not sure how this interacts with the upcoming requirement
that the data in a string be contiguous, but at least at
present, the implementation of the const operator[] could be
something like:
CharT const&
basic_string< ... >::eek:perator[]( size_t i ) const
{
static CharT const nul( 0 ) ;
return i < size() ? myRep[ i ] : nul ;
}
Is string's iterator required to behave the same way?
void foo( const string& s ) {
string::const_iterator it = s.begin();
string::value_type c = it[s.size()]; // well defined?
}

Good question. I don't think so. I can't find any text
requiring it, nor anything requiring s.begin() to have the
same behavior as s (although logically...).
 

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,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top