RE: [boost] Re: static sized strings

John Nagle wrote:
I think the relationship between "size()" and "capacity()" has to be such that if "size() < capacity()" you can add a character. So "capacity()" should not include the trailing null.
Makes sense.
For consistency with "<string>", "size()" can't include the trailing null.
This applies for both basic_string::size() and strlen( s ).
The big question is whether the size specified in the declaration (as in "char_string<80>") includes the trailing null.
I don't want to express an opinion on this until I've had some sleep. I can think of good arguments for both sides.
I have modified the sandbox implementation to make it easy to switch between the two models; it is currently using the 2nd model (adding space for the null). One possibility is putting the choice of models as a template parameter (e.g. bool need_null -- see comments in the sandbox code for an implementation), that way the decision is up to the programmer and not the library implementor.
Reece Dunn wrote:
John Nagle wrote:
Should the trailing null be counted in "capacity?"
This is a good point. At the moment fixed_string< n >::capacity() == n. It would therefore make sense that this be changed so that either:
[1] fixed_string< n >::capacity() == n - 1 -- this would seem counter-intuitive, as fixed_string< 1 > would not be able to store any characters!
[2] change CharT str[ n ] to CharT str[ n + 1 ] -- i.e. add an extra character for the trailing null. This would make more sense, as it is similar to: char * str = new char[ s.length() + 1 ];
I personally but a vote for solution 2, but what do other people think?
Regards, Reece _________________________________________________________________ Best Restaurant Giveaway Ever! Vote for your favorites for a chance to win $1 million! http://local.msn.com/special/giveaway.asp

From: "Reece Dunn" <msclrhd@hotmail.com>
John Nagle wrote:
Reece Dunn wrote:
John Nagle wrote: I think the relationship between "size()" and "capacity()" has to be such that if "size() < capacity()" you can add a character. So "capacity()" should not include the trailing null.
Makes sense.
I agree.
For consistency with "<string>", "size()" can't include the trailing null.
This applies for both basic_string::size() and strlen( s ).
Right.
The big question is whether the size specified in the declaration (as in "char_string<80>") includes the trailing null.
I don't want to express an opinion on this until I've had some sleep. I can think of good arguments for both sides.
I have modified the sandbox implementation to make it easy to switch between the two models; it is currently using the 2nd model (adding space for the null). One possibility is putting the choice of models as a template parameter (e.g. bool need_null -- see comments in the sandbox code for an implementation), that way the decision is up to the programmer and not the library implementor.
This is overkill. The purpose of fixed_string is to replace arrays of characters, otherwise, std::string would be the right replacement, right? Given that assumption, look to the syntax you're replacing: char s[] = "1234567890"; assert(10 == strlen(s)); size_t const LENGTH = 3; char t[LENGTH + 1]; strncpy(t, "ABCEFGHIJKLMNOP", LENGTH); assert(LENGTH == strlen(t)); Now do the same with the new class: fixed_string_base s(make_fixed_string("1234567890")); assert(10 == strlen(s)); assert(10 == s.size()); // using the new interface size_t const LENGTH = 3; char_string<LENGTH> t; t = "ABCEFGHIJKLMNOP"; assert(LENGTH == strlen(t)); assert(LENGTH == t.size()); // using the new interface (I know there is no make_fixed_string() -- yet -- but such a facility would be appropriate.) I think this clearer reveals that fixed_string's size parameter should specify the number of characters. Remember, one can use boost::array to manage a fixed size, non-string buffer. If buffer overrun protection is insufficient in boost::array, that should be fixed (or a new class should be added to Boost). Thus, fixed_string can ignore that usage.
Should the trailing null be counted in "capacity?"
This is a good point. At the moment fixed_string< n >::capacity() == n. It would therefore make sense that this be changed so that either:
[1] fixed_string< n >::capacity() == n - 1 -- this would seem counter-intuitive, as fixed_string< 1 > would not be able to store any characters!
Counter-intuitive, IMO.
[2] change CharT str[ n ] to CharT str[ n + 1 ] -- i.e. add an extra character for the trailing null. This would make more sense, as it is similar to: char * str = new char[ s.length() + 1 ];
That makes the most sense. I've always written such array allocations with the "+ 1" to clearly show that I'm accounting for the null terminator and to handle the case like I showed above in which the maximum length is a const "variable." -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

How do I update the length after using buffer() ? Only way I see is: FuncThatFillString(str.buffer(), str.capacity()); str.resize(strlen(str.c_str())); // c_str to avoid fixed_string overload

From: Martin <adrianm@touchdown.se>
How do I update the length after using buffer() ?
Only way I see is:
FuncThatFillString(str.buffer(), str.capacity()); str.resize(strlen(str.c_str())); // c_str to avoid fixed_string overload
That was the reason for a previous suggestion for ReleaseBuffer() (IIRC). It was a way for the client to have write access to the buffer and then tell the object it had control again. At that point, the object could recompute the length. I think MFC's CString has an overload of ReleaseBuffer() that permits the client to state the length resulting from its modifications of the buffer. (fixed_string would only need to constrain that length so as not to exceed the capacity() and this could be supported, too.) If the computed (or supplied) length exceeds the capacity, then fixed_string should throw an exception because that suggests the buffer was overrun. I previously suggested (or did I just think of it, but not mail it?) a proxy class for write access to the buffer. The proxy would be accessible via a buffer() mf, say, and would provide managed access to the buffer in the fixed_string from whence it came. The proxy can provide conversion operators to char * and char const *, and its dtor can recompute the length -- if not set by the client -- before returning control to the fixed_string. That would automate length verification, but you really don't want the proxy's dtor to throw an exception. (The only way around that, that I can think of, is to set a flag in fixed_string such that the next operation -- other than destruction -- performed on it would result in throwing an exception. That's unsatisfying for many reasons.) So, I'm thinking you'd do something like this: size_t character_count(FuncThatFillString( str.release_buffer(), str.capacity())); str.reclaim_buffer(); // invokes strlen() for you // or: str.reclaim_buffer(character_count); // you provide new length I chose the "release_buffer" and "reclaim_buffer" names to be a little more explicit. Either way, you'd need reciprocal terms. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (3)
-
Martin
-
Reece Dunn
-
Rob Stewart