Is it safe to use operator [] for std :: string

I am struggling with the old c-style interface. I have a function with a signature like this:

 /// if return_value == NULL only the length is returned
 void f( char * return_value, size_t * size_only_known_at_runtime); 

      

My question is, is the following code safe?

std::size required;
f( NULL, &required );
std::string s;
s.resize(required);
f( &s[0], &required );

      

Is there a better way to get data in a string?

+3


source to share


2 answers


Yes, it's safe, at least explicitly from C ++ 11. From [string.require], my kick is:

The char objects in the object basic_string

must be stored contiguous . That is, for any basic_string of the object s, then for all values ​​the n

identifier &*(s.begin() + n) == &*s.begin() + n

for which 0 <= n < s.size()

.

This was DR 530 . Until C ++ 11 this was not explicit in the standard, although it was done in practice anyway.

In C ++ 14, this requirement has moved to [basic.string]:

A basic_string

is a continuous container (23.2.1).



where [container.requirements.general]:

A neighboring container is a container that supports random access iterators (24.2.7) and whose member types are iterator

and const_iterator

are continuous iterators (24.2.1).

where [iterator.requirements.general]:

Iterators that additionally satisfy the requirement that for integral values n

and dereferenced values ​​of an iterator a

and (a + n)

, *(a + n)

equivalently *(addressof(*a) + n)

, are called continuous iterators.

+7


source


The question is, will the code

std::size_t required_size;
f( nullptr, &required_size );
std::string s;
s.resize( required_size );
f( &s[0], &required_size );

      

safe.

It depends on which C ++ standard is assumed, but since it is Undefined Behavior for case required_size

= 0 in C ++ 03 and C ++ 98, the general answer is no , it is not safe at all.


In C ++ 03, std::string

it was not formally guaranteed to have an adjacent buffer, but in practice all existing implementations had an adjacent buffer. Anyway, now after C ++ 11, where the standard included native buffer support, there will be no new C ++ 03 implementations with a non-contiguous buffer. Hence, this is not a problem.

The problem is rather that in C ++ 03 std::basic_string::operator[]

it was defined like this:



C ++ 03 §21.3.4 / 1 :

" Returns: If pos < size()

, returns data()[pos]

. Otherwise, if pos == size()

, version const

returns charT()

. Behavior is undefined.

So, for a string s

of s

size 0, in C ++ 03 it was Undefined Behavior ™; for indexing s[0]

.

In C ++ 11, the corresponding paragraph §21.4.3 / 2 instead states that the result is " *(begin() + pos)

if pos < size()

, otherwise, a reference to an object of type T

with a value charT()

; the reference value is not changed."


Here's the code that works no matter which C ++ standard the compiler implements:

std::size_t required_size;
f( NULL, &required_size );    // Establish required buffer size.
if( required_size > 0 )
{
    std::string s( required_size, '#' );
    f( &s[0], &required_size );
    s.resize( strlen( &s[0] ) );
}

      

+1


source







All Articles