From 8723547320221027516
X-Google-Language: ENGLISH,ASCII
X-Google-Thread: f78e5,953748e81bf9ec65
X-Google-Attributes: gidf78e5,public
From: kanze@gabi-soft.fr (J. Kanze)
Subject: Re: Class String of Standard
Date: 1998/06/11
Message-ID: <m3wwao3zw5.fsf@gabi-soft.fr>
X-Deja-AN: 361843235
Approved: Fergus Henderson <fjh@cs.mu.oz.au>
References: <6lcfss$q3v$1@duke.telepac.pt> <6lhfm1$q74$1@nnrp1.dejanews.com> <6lj1j8$34d$1@nnrp1.dejanews.com> <6lmmml$9sb$1@nnrp1.dejanews.com>
X-Original-Date: 11 Jun 1998 14:07:41 +0200
Organization: GABI Software, S�rl.
X-Auth: PGPMoose V1.1 PGP comp.std.c++ iQBFAgUANYBhY+EDnX0m9pzZAQEG1gF/T+gWtutNezZYy9E2bdBibcXIA11Tm4Wf 2CImlqdl7jrWz6YCgrsVB7yqSR+Vssrz =ewh3
Newsgroups: comp.std.c++


AllanW@my-dejanews.com writes:

|>  
|>  In article <6lj1j8$34d$1@nnrp1.dejanews.com>,
|>    James Kanze <jkanze@otelo.ibmmail.com> wrote:
|>  >
|>  > In article <6lhfm1$q74$1@nnrp1.dejanews.com>,
|>  >   AllanW@my-dejanews.com wrote:
|>  > > If c_string() is part of the ANSI/ISO
|>  > > standard, then I expect that most library vendors will always keep a
|>  > > trailing '\0' character in their internal buffers at all times.
|>  >
|>  > The two implementations I'm familiar with don't.  In fact, one doesn't
|>  > even maintain the string in sequential memory until c_str() or data() are
|>  > called.
|>  >
|>  > > The other methods are
|>  > > just too much problems.  Even if you add the '\0' on-demand, there's the
|>  > > problem that the (presumably const?) c_string() function might end up
|>  > > altering the internal char array.
|>  >
|>  > Any attempt to modify the string throught the pointer returned by c_str()
|>  > or data() is undefined behavior.  The implementation can thus ignore this
|>  > case.
|>  
|>  I wasn't referring to the possibility of the user code modifying the
|>  string.  I meant that if the string class adds '\0' to the end of the
|>  internal character data (incrementing the "allocated" size but not the
|>  "in use" size), then it might have to relocate that array of data to do
|>  so.  Depending on how iterators were implemented, this might invalidate
|>  all of them.

A call to c_str or data DOES invalidate all iterators and references
into the string.

    [...]
|>      * Never store the trailing '\0' character as part of the string's
|>        internal data.  (This seems to be how both of the two implementations
|>        that you are familiar with work).  Instead, calling c_str() allocates
|>        some memory, copies the characters into this allocated memory, adds
|>        the trailing '\0' byte, and returns it to the caller.
|>  
|>        But where is the memory for this copy?

    [...]
|>        --> A separate allocated C-style string, stored within the string
|>            object itself.  Any modification to the string contents will
|>            delete the C-style string, if it exists.  Calling the c_str()
|>            function will create it if neccesary, and then return the
|>            address.
|>  
|>            Possibly as good as this concept can go.  Once again, there's
|>            no limit on how many are active at once, it doesn't use any
|>            memory until it's needed, and all memory is eventually
|>            released.  Also, calling c_str() twice returns the same
|>            results (at the same address!) without performing the slow
|>            copy again.
|>  
|>            Unfortunately, the memory allocated for the copy takes up
|>            space until the string is changed or deleted.  If used a lot,
|>            this can cause most of the strings used to consume twice as
|>            much memory as would otherwise be needed.

This is the method used in the SGI rope class (which is pretty close to
the standard string).

In practice, at least in my own code, calls to c_str (or its equivalent
in my own string class) are fairly rare.  And of course, I'm running on
a machine with virtual memory (at least 200 Mega), so the extra memory
usage is irrelevant.

|>  My prediction (about which method "most vendors would probably use" was
|>  not based on any poll of C++ library vendors, but only on my own
|>  analysis and insight.  First, I looked at the other two solutions, and
|>  concluded that they both had problems.  Next, I decided that if I was
|>  implementing the string class myself, this is how I would have done it.
|>  Third, (and here's the only truely dangerous bit), I allowed myself the
|>  vanity of thinking that if I would do it this way, then many library
|>  vendors would too. (I've never been naive enough to think that ALL
|>  library vendors would do it my way, just some of them -- or, in this
|>  case, "most" of them.)  In the past, such vanity has gotten me into
|>  trouble, but not very often.  Library vendors are, on the whole,
|>  reasonable.  And chances are, if I think that something is reasonable,
|>  then at least a few others will think so too.  (We may all be mistaken,
|>  of course, but that's another story.)
|>  
|>   * * *
|>  
|>  So, Mr. Kanze, for the two implementations that you're familiar
|>  with, you said that one of them doesn't even maintain the string
|>  in sequential memory until c_str() or data() are called.  Let's
|>  call that one the NotSeq implementation, and the other one the
|>  IsSeq implementation.
|>  
|>  Does the NotSeq implementation use proxy object?  Or does it have
|>  a C-style string pointer as part of the string object?  If neither
|>  of these is correct, then how does it handle c_str()?

This is the SGI rope class, see above.

|>  Does the IsSeq implementation add '\0' to the internal array on
|>  demand?  If not, then how does it handle c_str()?

This is my own implementation; it does ensure that the allocated buffer
is always at least one larger than the capacity, so that it can append
the '\0' without reallocation, but that is simply because I can see no
interest, on a platform with virtual memory, in trying to save this
extra byte.

|>  Do you use c_str() much in any of your programs?  If so, have
|>  you found one of these implementations to be superior to the
|>  other, in memory consumption and/or run-time execution speed?
|>  Which one?  Do you know why?

In the past, I used the equivalent to c_str rather intensively, as I had
considerable code which was written to scan C style strings.  In more
recent code, much of this has been rewritten to use string iterators;
about the only remaining calls to c_str are for the filename argument to
fstream (or system level calls).

I've never done any actual measures -- my applications are NOT string
intensive, so I really don't care.  On the other hand, the SGI rope
class was written by one of the real specialists in this sort of thing,
precisely because contiguous allocation was too expensive for intensive
usage.

-- 
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient�e objet --
              -- Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]



