简体   繁体   中英

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

I'm fighting with an 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 the data into the string?

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

The char-like objects in a basic_string object shall be stored contiguously . That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size() .

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

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

A basic_string is a contiguous container (23.2.1).

where [container.requirements.general]:

A contiguous container is a container that supports random access iterators (24.2.7) and whose member types iterator and const_iterator are contiguous iterators (24.2.1).

where [iterator.requirements.general]:

Iterators that further satisfy the requirement that, for integral values n and dereferenceable iterator values a and (a + n) , *(a + n) is equivalent to *(addressof(*a) + n) , are called contiguous iterators .

The question is whether the code

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

is safe.

That depends on which C++ standard one assumes, but since it's Undefined Behavior for the case of required_size = 0 in C++03 and C++98, the general answer is no , it's not safe in general.


In C++03 std::string was not formally guaranteed to have a contiguous buffer, but in practice all extant implementation did have contiguous buffer. Anyway, now after C++11, where the contiguous buffer guarantee was formally incorporated in the standard, there will not appear any new C++03 implementations with non-contiguous buffer. Hence that isn't a problem.

The problem is rather that in C++03 std::basic_string::operator[] was defined as follows:

:

Returns: If pos < size() , returns data()[pos] . Otherwise, if pos == size() , the const version returns charT() . Otherwise, the behavior is undefined.

So, for a non- const string s of size 0, in C++03 it was Undefined Behavior™ to do the indexing s[0] .

In C++11 the corresponding paragraph §21.4.3/2 says instead that the result is “ *(begin() + pos) if pos < size() , otherwise a reference to an object of type T with value charT() ; the referenced value shall not be modified.”


Here's code that works regardless of 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] ) ); } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM