non-const version of std::string::data()

D

dp1978x

Hi,

is the following legal?

std::string x;
// ...
assert (!x.empty());
x.data()[0] = 'b';

I think not, AFAIK there's no non-const version of "data()", could
someone confirm?

How about this then:

std::string x;
// ...
assert (!x.empty());
const_cast <char *>(x.data())[0] = 'b';

Background: I have a C library that fills array of characters passed
to it by the caller. I need to convert the returned strings to
std::string. I would prefer to do this directly w/o allocating any
temporaries.

Thanks,
D.
 
D

dp1978x

(e-mail address removed) kirjutas:
is the following legal?
std::string x;
// ...
assert (!x.empty());
x.data()[0] = 'b';
I think not, AFAIK there's no non-const version of "data()", could
someone confirm?

There is: &x[0]

hth
Paavo

Okay, bad example. I need a non-const pointer to the underlying array
of characters, so that all characters in the range [0..length) are
addressible.

So will "(&x[0])[n]" where 0 <= n < length work?

D.
 
J

Juha Nieminen

Paavo said:
More verbosely, I should probably note that the contiguity of the string
buffer obtained by &x[0] is not guaranteed by the standard, but all known
C++ implementations are following that, and the requirement will be present
in the next standard AFAIK.

Do practical implementations of std::string always use a contiguous
array (in the same as std::vector) because it makes it much more
efficient for the std::string::c_str() to do its job (basically it just
needs to append a '\0' and then return a pointer to the array)?
 
D

dp1978x

(e-mail address removed) kirjutas:

Yes, I understood your question, it should work in practice (see my other
post). If you want strict guarantee also by the current standard, use
std::vector<char>.

Paavo

Thanks! So just to be clear: in the current standard operator[] in
vector<> _does_ guaruantee this, but not basic_string?

D.
 
D

dp1978x

Do practical implementations of std::string always use a contiguous
array (in the same as std::vector) because it makes it much more
efficient for the std::string::c_str() to do its job (basically it just
needs to append a '\0' and then return a pointer to the array)?

I would think most implementations always keep the buffer up-to-date
w.r.t. c_str() by NUL-terminating it in every modifier function, so
c_str() simply returns a pointer. Not that it matters much.
 
J

James Kanze

is the following legal?
  std::string x;
  // ...
  assert (!x.empty());
  x.data()[0] = 'b';
I think not, AFAIK there's no non-const version of "data()",
could someone confirm?

There isn't yet. I'd heard that there was supposed to be one
soon, but I don't see it in my copy of the CD, so maybe I'm
mistaken. In the meantime, &x[0] will work if the string isn't
empty.
How about this then:
  std::string x;
  // ...
  assert (!x.empty());
  const_cast <char *>(x.data())[0] = 'b';
Background: I have a C library that fills array of characters
passed to it by the caller. I need to convert the returned
strings to std::string. I would prefer to do this directly w/o
allocating any temporaries.

I think you're better off using &x[0]. It seems to be the
accepted idiom for std::vector (which will have a non-const
data() function).
 
J

James Kanze

Paavo said:
More verbosely, I should probably note that the contiguity
of the string buffer obtained by &x[0] is not guaranteed by
the standard, but all known C++ implementations are
following that, and the requirement will be present in the
next standard AFAIK.
Do practical implementations of std::string always use a
contiguous array (in the same as std::vector) because it makes
it much more efficient for the std::string::c_str() to do its
job (basically it just needs to append a '\0' and then return
a pointer to the array)?

I think in practice you're right. (Not just that all
implementations use contiguous memory, but that this is part of
the motivation as well.) I think that originally, however, it
was believed that C style strings would be rare enough that
optimization considerations when interfacing to them wouldn't be
an issue. (Wishful thinking, obviously, but there were some
real optimists around.)
 
T

Thomas J. Gritzan

Paavo said:
Paavo Helde said:
Juha Nieminen said:
Paavo Helde wrote:
More verbosely, I should probably note that the contiguity of the
string buffer obtained by &x[0] is not guaranteed by the standard,
but all known C++ implementations are following that, and the
requirement will be present in the next standard AFAIK.
Do practical implementations of std::string always use a contiguous
array (in the same as std::vector) because it makes it much more
efficient for the std::string::c_str() to do its job (basically it
just needs to append a '\0' and then return a pointer to the array)?
It also has to do with thread-safety. Although the current standard
does not mention multithreading, a quality implementation attempts to
provide some useful support for it. For the string objects, them being
value types, this means that they should not mutate physically in
const member functions.

Sorry, forgot to mention *why* they should not mutate. The reason is that
in another thread the client code may held (const) references or pointers
to certain chars inside the buffer, via the operator[], and it expects
them remain valid while no non-const memmber function is called on the
string.

A class with a less promiscuous interface could mutate inner details also
in const member functions.

A const member function shouldn't mutate chars inside the range of valid
characters [begin, end), but the terminating '\0' will be set outside
this range. So I think appending the zero on a call to c_str() would be
correct (that is, reserving the space for '\0' every time, but only
setting the actual value on a call to c_str).
 
J

James Kanze

[...]
Sorry, forgot to mention *why* they should not mutate. The
reason is that in another thread the client code may held
(const) references or pointers to certain chars inside the
buffer, via the operator[], and it expects them remain valid
while no non-const memmber function is called on the string.
A class with a less promiscuous interface could mutate inner
details also in const member functions.
A const member function shouldn't mutate chars inside the
range of valid characters [begin, end), but the terminating
'\0' will be set outside this range. So I think appending the
zero on a call to c_str() would be correct (that is, reserving
the space for '\0' every time, but only setting the actual
value on a call to c_str).

Exactly. It's an implementation detail.

Note that calls to std::basic_string<>::data() and
std::basic_string<>::c_str() may invalidate iterators,
references and pointers into the string, so an implementation is
not required to even reserve the space. And unless the code
documents otherwise, you have to assume that passing a string to
a function via a string const& also invalidates iterators,
references and pointers into that string. (The string interface
is funny in that regard; calling the const functions data() or
c_str() may invalidate iterators, but calling a non-const
operator[] or at() may not, at least in some circumstances.)
 

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,780
Messages
2,569,609
Members
45,253
Latest member
BlytheFant

Latest Threads

Top