Topic: does basic_string::c_str limit implementation?
Author: sirwillard@my-dejanews.com
Date: 1999/01/20 Raw View
In article <$hUKEaAKgyn2Ew95@robinton.demon.co.uk>,
Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> Objects do not have scope, they have lifetimes. Identifiers have scope.
Point noted. I believe we were both refering to lifetime and not scope. If
I'm wrong, the original post makes even less sense to me then it already did.
Terms like these can lead to confusion when used improperly.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ 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 ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/17 Raw View
In article <77lvh0$t1r$1@nnrp1.dejanews.com>, sirwillard@my-dejanews.com
writes
>Object's have scope, not the other way around. Objects placed on
>the heap have scope from new to delete, the exact issue that brings us to why
>delete on a const pointer is valid.
Objects do not have scope, they have lifetimes. Identifiers have scope.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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 ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/01/14 Raw View
sirwillard@my-dejanews.com sbnaran@uiuc.edu wrote:
>> Changing the thread a little, I wish it were illegal to call delete,
>> delete[], or a destructor on a pointer-to-const. This would make
>> C++ a little safer as deleting an object is, by common sense, a way
>> of changing it.
I disagree. There are too many cases where my objects point to
strings (the char[] type, not std:string) using const pointers;
the class does all the allocation and deallocation of the string,
but wants the string to remain inviolate once it's been allocated
and initialized. But when it comes time to delete the string, I
shouldn't care whether it's const or not, since I'm (e.g., my
class) in complete control of its existence.
For example:
class FileStuff
{
public:
/**/ ~FileStuff();
/**/ FileStuff();
void setName(const char *n);
...
protected:
const char * m_name; // [D]
...
};
FileStuff::FileStuff():
m_name(NULL)
{
...
}
FileStuff::~FileStuff()
{
// Deallocate existing name, if any
delete m_name, m_name = NULL; // [1b]
...
}
void FileStuff::setName(const char *n)
{
// Deallocate existing name, if any
delete m_name; // [1a]
// Allocate and copy new name
char * c;
c = new char[strlen(n)+1];
if (c != NULL)
strcpy(c, n);
m_name = c; // [2]
}
At point [2], the string pointed to by m_name has been allocated
and initialized; further changes to the string are to be avoided.
Hence, we declare m_name as a pointer-to-const at [D], so the string
won't be inadvertently altered by other member functions. If
nothing else, declaring it 'const' makes this intent more obvious.
At points [1a] and [1b], we wish to deallocate the string. At
this time, we don't care whether it's const or not, because we're
getting rid of it, and our class should have total control over
it. Requiring a cast or the use of a non-const temporary variable
(which is how some current compilers behave), is a real pain.
It's also counterintuitive to the notion of member ownership.
-- David R. Tribble, dtribble@technologist.com --
---
[ 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 ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/14 Raw View
On 14 Jan 99 21:14:18 GMT, David R Tribble <dtribble@technologist.com> wrote:
>I disagree. There are too many cases where my objects point to
>strings (the char[] type, not std:string) using const pointers;
>the class does all the allocation and deallocation of the string,
>but wants the string to remain inviolate once it's been allocated
>and initialized. But when it comes time to delete the string, I
>shouldn't care whether it's const or not, since I'm (e.g., my
>class) in complete control of its existence.
If you say that the sort of code below is common coding practice,
then I guess it is unreasonable to add the rule that you can't
apply delete to a pointer-to-const.
>For example:
>
> class FileStuff
> {
> public:
> /**/ ~FileStuff();
> /**/ FileStuff();
> void setName(const char *n);
> ...
>
> protected:
> const char * m_name; // [D]
> ...
> };
>
>
> FileStuff::FileStuff():
> m_name(NULL)
> {
> ...
> }
>
> FileStuff::~FileStuff()
> {
> // Deallocate existing name, if any
> delete m_name, m_name = NULL; // [1b]
> ...
> }
However, this has never occurred in my designs. Whenever I've
needed to make the pointed to object const, then I either
[X] Declare it as "T*" and remember to treat it as "const T*"
in all my member functions (ok for a simple class).
[X] Declare it as "good_ptr<T>" where the class good_ptr gives
me logical constness -- ie, it returns "T*" in a non-const
member function and "const T*" in a const member function.
Furthermore, I use a class const_good_ptr that does not
have the operator-> function that returns a "T*". Ie,
it only has the operator-> that returns "const T*". To
delete the object, I do a const_cast<T*>(...).
The above two guidelines still seem safer to me than the rule
that you can delete a pointer to const. But if a lot of code
is written in the manner of your example, then I guess it is
too late too change.
Of course, even if we changed the rule so that you can't
apply delete to a pointer-to-const, there's still no safety
against the following kind of thing,
void f(std::vector<int>& v) { delete[] &v[0]; }
We need a rule that delete can't be applied to a pointer that
is a member of a container, because the container will be
deleting the elements in the container.
The main conceptual point is this: Only the scope that owns
the object -- ie, the scope that did "t=new T(...)" -- should
be able to delete the object -- ie, do "delete t".
Currently, I enforce this rule through coding guidelines.
My "const" idea was an attempt to enforce this rule through
the language. That is, the pointer is stored inside the
class FileStuff as a char* so that it can be deleted, but
this pointer is returned to the outside world as const char*,
so that it can't be deleted.
But thinking about it know, I see that my proposed const
solution doesn't really achieve the above conceptual point.
We need context sensitive rules to achieve the above
ownership safety.
Still, applying delete to a pointer and calling a destructor
on an object still seems like a way of changing the object,
and on these grounds alone, we should not be able to delete
a pointer-to-const.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]
Author: sirwillard@my-dejanews.com
Date: 1999/01/14 Raw View
In article <slrn79qcnt.abk.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
>
> On 13 Jan 1999 17:32:28 GMT, sirwillard@my-dejanews.com
> > sbnaran@KILL.uiuc.edu wrote:
>
> >[snip example of a hack for calling a non-const member function through the
> >destructor]
> >
> >Such coding is obvious "shooting off your foot" programming. One can give a
> >million examples of such things. For instance, the whole contrived example is
> >no more dangerous or less obvious than the statement:
> >
> >const_cast<X*>(&x)->kill();
> >
> >Further, the code you used will produce undefined behavior, since the
> >destructor will be called twice.
>
> Yes, I guess its the old theme of fraud versus accident. I still
> think the above code may arise by accident.
I don't. When does one ever call the destructor directly with code such as
x.~X ()? With the exception of implementing placement new/delete, I can't
think of an instance when I'd ever call this. It's a red flag as large as
the const_cast, if not larger.
> >> Yes, the const_cast is ugly for those cases where we must delete a
> >> pointer to cost. But these cases are in rare, it seems to me.
> >
> >Why are they rare? I think they'd be awfully common.
>
> Really. My classes that hold pointer to implementation data
> fields declare the implementation as non-const, as we usually
> want to call non-const member functions. Eg,
> class X { Thing * thing; ... };
> Member functions of class X can call thing->function(),
> where Thing::function() may or may not be const.
If we declare a const instance of a class with a pointer, said pointer is a
const pointer. Makes it awfully difficult to delete said pointer in the
destructor, no?
> The main reason for me proposing this rule is that in scope
> X, pointers to objects owned by scope X like our X::thing
> above, are non-const, and hence, in "delete thing", 'thing'
> is a pointer to non-const. I've never deleted a pointer to
> const. Now I could be wrong here. What do others do?
At least you've never knowingly deleted a pointer to const. Also, I have
problems with "pointers to objects owned by scope X". If the object is
placed on the heap, it is not owned by any scope (if scopes can own an
object). Object's have scope, not the other way around. Objects placed on
the heap have scope from new to delete, the exact issue that brings us to why
delete on a const pointer is valid.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/15 Raw View
In article <slrn79sr93.nlt.sbnaran@localhost.localdomain>, Siemel Naran
<sbnaran@localhost.localdomain.COM> writes
>The main conceptual point is this: Only the scope that owns
>the object -- ie, the scope that did "t=new T(...)" -- should
>be able to delete the object -- ie, do "delete t".
I do not think you could possibly mean this. How do you propose to
implement factory functions with such a rule.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ 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 ]
Author: saroj@bear.com
Date: 1999/01/15 Raw View
In article <369E4591.C57C6CFF@technologist.com>,
David R Tribble <dtribble@technologist.com> wrote:
> For example:
>
> class FileStuff
> {
> public:
> /**/ ~FileStuff();
> /**/ FileStuff();
> void setName(const char *n);
> ...
>
> protected:
> const char * m_name; // [D]
> ...
> };
>
[snipped]
>
> FileStuff::~FileStuff()
> {
> // Deallocate existing name, if any
> delete m_name, m_name = NULL; // [1b]
> ...
> }
>
> void FileStuff::setName(const char *n)
> {
> // Deallocate existing name, if any
> delete m_name; // [1a]
>
> // Allocate and copy new name
> char * c;
> c = new char[strlen(n)+1];
> if (c != NULL)
> strcpy(c, n);
> m_name = c; // [2]
> }
>
A small correction : at point [1a] call delete[] m_name (array delete).
- Saroj Mahapatra
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/01/13 Raw View
AllanW@my-dejanews.com wrote:
>
> In article <slrn79gcqc.33v.sbnaran@localhost.localdomain>,
> sbnaran@uiuc.edu wrote:
....
> > Fine. But everyone, including experts, make mistakes. So we
> > should stay away from dangerous language constructs as much
> > as possible, and this includes staying away from 'mutable' as
> > much as possible.
>
> By that same logic, we should avoid classes with friends,
> member variables that are pointers, any class with multiple
> inheritance, standard containers and iterators, new-style
> casts, and pretty much everything in C++ that isn't also
> in C.
I wouldn't say that the standard containers and iterators are especially
dangerous.
With that exception, those are all good things to avoid. Not absolutely,
of course, but none of them are things that should be introduced
unnecessarily.
---
[ 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 ]
Author: sbnaran@dirac.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/13 Raw View
On 12 Jan 1999 18:28:38 GMT, sirwillard@my-dejanews.com
> sbnaran@uiuc.edu wrote:
>> Changing the thread a little, I wish it were illegal to call delete,
>> delete[], or a destructor on a pointer-to-const. This would make
>> C++ a little safer as deleting an object is, by common sense, a way
>> of changing it.
>
>No, I don't agree that that is common sense.
/*
Suppose class X had a non-const member kill() that deletes the
elements in X. The destructor ~X() calls kill(). Given an 'x'
of type "X const *", we can't do x->kill() as this tries to modify
a const object. But we can do x->~X(), and now the call to kill()
works.
*/
struct X
{
X();
void kill();
~X() { kill(); }
};
int main()
{
const X x;
x.kill(); // error
x.~X(); // ok
}
-------------------------------------------------------------
>> The rule should be if you want to do "delete x",
>> then 'x' should be a pointer-to-nonconst. This means that we may
>> have to use a const_cast to make the delete statement work.
>
>An awfully ugly hack just to prevent leaking memory, and it doesn't eliminate
>the problem _you_ perceive with const.
Yes, the const_cast is ugly for those cases where we must delete a
pointer to cost. But these cases are in rare, it seems to me.
One reason to use pointers is to take advantage of polymorphism.
Another reason to use pointers is to get cheap, fast copies.
Perhaps we don't want to use reference counted objects, so we
use ordinary pointers. Here are two examples.
1. Suppose we have a list of Activity objects std::list<Activity>.
class Activity is not polymorphic.
2. Suppose we have a list of Persons objects std::list<Person*>.
class Person is polymorphic.
Now suppose we want all Activity objects that represent activities
that are due tomorrow. Suppose also that we want all people whose
names start with the letter 'L'. This calls for two functions
(should be 'std::list', but I want everything to fit on the screen):
list<Activity const *> activities_due_tomorrow(const list<Activity>&);
list<Person const *> people_with_name(const list<Person*>, char name);
In the first function, class Activity is not reference counted, so
we can't use std::list<Activity> for the return type. So we use
pointers instead, returning a std::list<Activity const *>. Of course,
the allows us to only call const functions on the returned Activity
objects, such as Activity::show. But this is ok for our application.
Surely we don't want the client calling this function to be able to
call "delete p" on one of the objects in the list. So the 'const' is
there as a kind of assurance.
In the second function, we have to return a list of pointers as the
objects are polymorphic. But once again, we want the assurance that
the client won't call 'delete' on one of the returned objects. So we
declare the return as a bunch of pointers to const.
>> But
>> for stack objects, deletion is automatic and a const_cast should
>> not be required. I think this would be a nice change to C++.
>
>So, destructors can be called on const objects implicitly but not explicitly.
>Doesn't that strike you as a lot more confusing to programmers then the
>current view that lifetime is not part of an objects state, and therefore not
>affected by const?
Yes, it is confusing, but helpful in view of the two examples above.
Alternatively, we could say that calling a destructor on a const object
is ok, but calling delete on a pointer to const is an error.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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 ]
Author: sirwillard@my-dejanews.com
Date: 1999/01/13 Raw View
In article <slrn79njrk.qqn.sbnaran@dirac.ceg.uiuc.edu>,
sbnaran@KILL.uiuc.edu wrote:
> On 12 Jan 1999 18:28:38 GMT, sirwillard@my-dejanews.com
> > sbnaran@uiuc.edu wrote:
>
> >> Changing the thread a little, I wish it were illegal to call delete,
> >> delete[], or a destructor on a pointer-to-const. This would make
> >> C++ a little safer as deleting an object is, by common sense, a way
> >> of changing it.
> >
> >No, I don't agree that that is common sense.
[snip example of a hack for calling a non-const member function through the
destructor]
Such coding is obvious "shooting off your foot" programming. One can give a
million examples of such things. For instance, the whole contrived example is
no more dangerous or less obvious than the statement:
const_cast<X*>(&x)->kill();
Further, the code you used will produce undefined behavior, since the
destructor will be called twice.
> >> The rule should be if you want to do "delete x",
> >> then 'x' should be a pointer-to-nonconst. This means that we may
> >> have to use a const_cast to make the delete statement work.
> >
> >An awfully ugly hack just to prevent leaking memory, and it doesn't eliminate
> >the problem _you_ perceive with const.
>
> Yes, the const_cast is ugly for those cases where we must delete a
> pointer to cost. But these cases are in rare, it seems to me.
Why are they rare? I think they'd be awfully common.
> One reason to use pointers is to take advantage of polymorphism.
> Another reason to use pointers is to get cheap, fast copies.
> Perhaps we don't want to use reference counted objects, so we
> use ordinary pointers.
You've missed a LOT of other uses for pointers. The most obvious is simply to
place the object on the heap (there are reasons to want this).
[snip discussion of containers where you want to insure the "user" can't
delete the objects]
Firstly, I think such concerns are irrelavent. Obviously, so long as the
pointer is in the container, the contianer owns the object and the "user"
shouldn't be deleting it. For cases where ownership must be well defined and
you can't rely on the "user" from ignoring the rules, a smart pointer is a
better solution than for the language to redefine the meaning of const (which
doesn't include lifetime).
> >> But
> >> for stack objects, deletion is automatic and a const_cast should
> >> not be required. I think this would be a nice change to C++.
> >
> >So, destructors can be called on const objects implicitly but not explicitly.
> >Doesn't that strike you as a lot more confusing to programmers then the
> >current view that lifetime is not part of an objects state, and therefore not
> >affected by const?
>
> Yes, it is confusing, but helpful in view of the two examples above.
> Alternatively, we could say that calling a destructor on a const object
> is ok, but calling delete on a pointer to const is an error.
A little more intuitive, but doesn't go far enough and will lead to confusion
in specific circumstances.
Sorry, you've not convinced me that const should dictate the lifetime of an
object (mostly because I don't see how it could).
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/13 Raw View
In article <369BF332.4932479@wizard.net>, James Kuyper
<kuyper@wizard.net> writes
>> By that same logic, we should avoid classes with friends,
>> member variables that are pointers, any class with multiple
>> inheritance, standard containers and iterators, new-style
>> casts, and pretty much everything in C++ that isn't also
>> in C.
>
>I wouldn't say that the standard containers and iterators are especially
>dangerous.
>
>With that exception, those are all good things to avoid. Not absolutely,
>of course, but none of them are things that should be introduced
>unnecessarily.
You mean you prefer C-style casts? ;-)
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ 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 ]
Author: AllanW@my-dejanews.com
Date: 1999/01/13 Raw View
In article <369BF332.4932479@wizard.net>,
James Kuyper <kuyper@wizard.net> wrote:
> AllanW@my-dejanews.com wrote:
> >
> > In article <slrn79gcqc.33v.sbnaran@localhost.localdomain>,
> > sbnaran@uiuc.edu wrote:
> ....
> > > Fine. But everyone, including experts, make mistakes. So we
> > > should stay away from dangerous language constructs as much
> > > as possible, and this includes staying away from 'mutable' as
> > > much as possible.
> >
> > By that same logic, we should avoid classes with friends,
> > member variables that are pointers, any class with multiple
> > inheritance, standard containers and iterators, new-style
> > casts, and pretty much everything in C++ that isn't also
> > in C.
>
> I wouldn't say that the standard containers and iterators are especially
> dangerous.
>
> With that exception, those are all good things to avoid. Not absolutely,
> of course, but none of them are things that should be introduced
> unnecessarily.
Well, of course. I wouldn't want to introduce for()-loops
unnecessarily, either. But this doesn't mean that I consider them to
be dangerous. I consider them to be useful when they are useful, and
extraneous when they are not.
---
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/14 Raw View
On 13 Jan 1999 17:32:28 GMT, sirwillard@my-dejanews.com
> sbnaran@KILL.uiuc.edu wrote:
>[snip example of a hack for calling a non-const member function through the
>destructor]
>
>Such coding is obvious "shooting off your foot" programming. One can give a
>million examples of such things. For instance, the whole contrived example is
>no more dangerous or less obvious than the statement:
>
>const_cast<X*>(&x)->kill();
>
>Further, the code you used will produce undefined behavior, since the
>destructor will be called twice.
Yes, I guess its the old theme of fraud versus accident. I still
think the above code may arise by accident.
>> Yes, the const_cast is ugly for those cases where we must delete a
>> pointer to cost. But these cases are in rare, it seems to me.
>
>Why are they rare? I think they'd be awfully common.
Really. My classes that hold pointer to implementation data
fields declare the implementation as non-const, as we usually
want to call non-const member functions. Eg,
class X { Thing * thing; ... };
Member functions of class X can call thing->function(),
where Thing::function() may or may not be const.
The main reason for me proposing this rule is that in scope
X, pointers to objects owned by scope X like our X::thing
above, are non-const, and hence, in "delete thing", 'thing'
is a pointer to non-const. I've never deleted a pointer to
const. Now I could be wrong here. What do others do?
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/01/14 Raw View
Francis Glassborow wrote:
>
> In article <369BF332.4932479@wizard.net>, James Kuyper
> <kuyper@wizard.net> writes
> >> By that same logic, we should avoid classes with friends,
> >> member variables that are pointers, any class with multiple
> >> inheritance, standard containers and iterators, new-style
> >> casts, and pretty much everything in C++ that isn't also
> >> in C.
> >
> >I wouldn't say that the standard containers and iterators are especially
> >dangerous.
> >
> >With that exception, those are all good things to avoid. Not absolutely,
> >of course, but none of them are things that should be introduced
> >unnecessarily.
>
> You mean you prefer C-style casts? ;-)
No, those should be avoided too. I should have read it more closely.
---
[ 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 ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/01/07 Raw View
sbnaran@localhost.localdomain.COM (Siemel Naran) writes:
>I didn't think of the idea of adding a null char in the accessor
>function basic_string::c_str(). In any case, it might not be
>possible to expand the internal buffer when c_str is called;
>string::operator+=(char) has to ensure that the internal buffer
>has space for the null char, even if it hasn't bothered to put
>the null char there. This is because expanding the buffer may
>mean relocating it. But in the constant member function
>string::c_str() const, the buffer has type "char *const", so
>it can't be relocated. Unless it is mutable, but that may be
>a messy choice.
What's messy about using mutable for that case?
It seems to me to be exactly the sort of case that
mutable was designed for.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh> | but source code lives forever"
PGP: finger fjh@128.250.37.3 | -- leaked Microsoft memo.
[ 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 ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/08 Raw View
sbnaran@uiuc.edu wrote:
> On 07 Jan 99 03:27:02 GMT, AllanW@my-dejanews.com
>
> >The other choice is for c_str to add the null terminator before
> >returning. If the internal buffer does not already have enough
> >space for a null terminator, it must be expanded to make room.
> >Then, the buffer position one past the end of the string is set
> >to null, and the address is returned.
...
> In any case, it might not be
> possible to expand the internal buffer when c_str is called;
Then an exception is thrown because there is not enough freestore.
> string::operator+=(char) has to ensure that the internal buffer
> has space for the null char, even if it hasn't bothered to put
> the null char there.
No, because opreator += is not used.
> This is because expanding the buffer may
> mean relocating it. But in the constant member function
> string::c_str() const, the buffer has type "char *const", so
> it can't be relocated. Unless it is mutable, but that may be
> a messy choice.
Not messy at all. I will assume the string already grows its internal
storage in chunks, so it already has some resize function that rounds up
the size passed in. All c_str() has to do is grow the internal storage by
one character, then set it to null:
class string {
char* mutable chars;
// mutable because pointer may change when length is changed
size_t len; // conceptual length as user sees string
size_t mutable alloc_len;
// actual allocated length of chars array
// used to prevent unnecessary calls to resize chars array
// reallocate chars to have at least s chars available
// probably rounds up to nearest power of two,
// or a multiple of some value
void resize_alloc_chars( size_t ) const;
public:
// constructors omitted
char const* c_str() const
{
resize_alloc_chars( len + 1 );
chars [len] = '\0';
return chars;
}
// for comprehension
string& operator += ( char const c )
{
resize_alloc_chars( len + 1 );
chars [len] = c;
++len;
return *this;
}
};
The use of mutable and const is entirely reasonable here, because const
says that what the user sees will remain the same through those
operations, which is the case.
Reallocation of the internal chars array doesn't affect the external
representation, assuming the resize is done with an appropriate value.
Perhaps you have an idea that is less messy? I consider this to be an
elegant, simple, practically free, and non-error-prone way of providing
the c_str() functionality.
--
IF YOU DON'T THINK FOR YOURSELF, SOMEONE ELSE WILL
Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
---
[ 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 ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/08 Raw View
On 08 Jan 99 05:05:22 GMT, Gargantua Blargg <blargg@flash.net> wrote:
>sbnaran@uiuc.edu wrote:
>> In any case, it might not be
>> possible to expand the internal buffer when c_str is called;
>
>Then an exception is thrown because there is not enough freestore.
No, I was just saying that the non-const functions like op+= and
append should expand the buffer so that it already has the space
for the null char available. This way, c_str does not have to
do any resizing. I prefer not to use 'mutable'. The "might not
be possible" arises because we may have to relocate the pointer.
The problem with 'mutable' is twofold. First, we might
accidentally change the variable in a const function, and the
compiler won't be able to issue a compiler error. Second, a
mutable variable of type "T" in a non-const object has type "T"
in a const object, not "const T". This prevents the optimization
of looking up the value and storing it in a register -- fancy
term: const propogation -- because the value might change at any
time.
Anyway, this is getting off-topic for comp.std.c++. My original
thought was that the existence of string::c_str limits the
implementation, but this is not so. Details of how to implement
aren't for this newsgroup, so we should relocate to
comp.lang.c++.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]
Author: Matt Austern <austern@sgi.com>
Date: 1999/01/10 Raw View
blargg@flash.net (Gargantua Blargg) writes:
> The use of mutable and const is entirely reasonable here, because const
> says that what the user sees will remain the same through those
> operations, which is the case.
>
> Reallocation of the internal chars array doesn't affect the external
> representation, assuming the resize is done with an appropriate value.
It does, actually: it invalidates references and iterators. This is
a major effect on the external view of the string.
The standard explicitly permits the const member functions c_str() and
data() to invalidate references and iterators, so an implementation
where c_str() does this is conforming. However, it is not
transparent. The user can tell, and must know, that c_str() is a
const member function that nevertheless performs non-const operations.
---
[ 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 ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/10 Raw View
sbnaran@uiuc.edu wrote:
> The problem with 'mutable' is twofold. First, we might
> accidentally change the variable in a const function, and the
> compiler won't be able to issue a compiler error.
Yes mutable is a tool for experts - and I won't use a std library
implementation not written by an expert...
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ 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 ]
Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/10 Raw View
On 10 Jan 99 03:14:09 GMT, Valentin Bonnard <bonnardv@pratique.fr> wrote:
>sbnaran@uiuc.edu wrote:
>> The problem with 'mutable' is twofold. First, we might
>> accidentally change the variable in a const function, and the
>> compiler won't be able to issue a compiler error.
>
>Yes mutable is a tool for experts - and I won't use a std library
>implementation not written by an expert...
Fine. But everyone, including experts, make mistakes. So we
should stay away from dangerous language constructs as much
as possible, and this includes staying away from 'mutable' as
much as possible.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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 ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/11 Raw View
In article <slrn79gcqc.33v.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> On 10 Jan 99 03:14:09 GMT, Valentin Bonnard <bonnardv@pratique.fr> wrote:
> >sbnaran@uiuc.edu wrote:
>
> >> The problem with 'mutable' is twofold. First, we might
> >> accidentally change the variable in a const function, and the
> >> compiler won't be able to issue a compiler error.
> >
> >Yes mutable is a tool for experts - and I won't use a std library
> >implementation not written by an expert...
>
> Fine. But everyone, including experts, make mistakes. So we
> should stay away from dangerous language constructs as much
> as possible, and this includes staying away from 'mutable' as
> much as possible.
What about accidently modifying a variable in non-const member functions?
Perhaps we should ban the use of any non-const member variables. But by
this logic we shouldn't even use C++. What if we call a wrong function
somewhere? What if we use the wrong variable? int when we should use long?
There is some level that the programmer must trust themselves to write
correct code. I think the class level is fine. If they can't implement
their class correctly, then they shouldn't be using C++, or possibly
coding at all.
--
D.A.R.E. to say no to majority. Think for yourself.
Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
---
[ 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 ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/11 Raw View
Matt Austern <austern@sgi.com> wrote:
> blargg@flash.net (Gargantua Blargg) writes:
>
> > The use of mutable and const is entirely reasonable here, because const
> > says that what the user sees will remain the same through those
> > operations, which is the case.
> >
> > Reallocation of the internal chars array doesn't affect the external
> > representation, assuming the resize is done with an appropriate value.
>
> It does, actually: it invalidates references and iterators. This is
> a major effect on the external view of the string.
I don't agree, but this is due to my definition of "external view". I
think this encompasses the externally-accessible state of the object,
namely the string of characters, and nothing more. Iterator invalidation
is another issue. This shows that logical constness is not enough to
describe a member function's effect on behavior that can be externally
*detected*. The fact that c_str() is a const member function proves this.
> The standard explicitly permits the const member functions c_str() and
> data() to invalidate references and iterators, so an implementation
> where c_str() does this is conforming. However, it is not
> transparent. The user can tell, and must know, that c_str() is a
> const member function that nevertheless performs non-const operations.
Agreed.
--
D.A.R.E. to say no to majority. Think for yourself.
Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
---
[ 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 ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1999/01/12 Raw View
blargg@flash.net (Gargantua Blargg) writes:
>Matt Austern <austern@sgi.com> wrote:
>
>> blargg@flash.net (Gargantua Blargg) writes:
>>
>> > The use of mutable and const is entirely reasonable here, because const
>> > says that what the user sees will remain the same through those
>> > operations, which is the case.
>> >
>> > Reallocation of the internal chars array doesn't affect the external
>> > representation, assuming the resize is done with an appropriate value.
>>
>> It does, actually: it invalidates references and iterators. This is
>> a major effect on the external view of the string.
>
>I don't agree, but this is due to my definition of "external view". I
>think this encompasses the externally-accessible state of the object,
>namely the string of characters, and nothing more. Iterator invalidation
>is another issue. This shows that logical constness is not enough to
>describe a member function's effect on behavior that can be externally
>*detected*.
Yes. If an object is const, that means that it won't change during its
lifetime. But constness says nothing about what the lifetime will be.
It's quite legal to destroy or delete a pointer to a const object.
void f(const T *p1, const T *p2) {
delete p1; // legal
p2->~T(); // legal
}
References and iterators become invalidated when the lifetime of what
they refer to ends. Constness doesn't provide any guarantees about
lifetimes not ending.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh> | but source code lives forever"
PGP: finger fjh@128.250.37.3 | -- leaked Microsoft memo.
---
[ 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 ]
Author: AllanW@my-dejanews.com
Date: 1999/01/12 Raw View
In article <slrn79gcqc.33v.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> On 10 Jan 99 03:14:09 GMT, Valentin Bonnard <bonnardv@pratique.fr> wrote:
> >sbnaran@uiuc.edu wrote:
>
> >> The problem with 'mutable' is twofold. First, we might
> >> accidentally change the variable in a const function, and the
> >> compiler won't be able to issue a compiler error.
> >
> >Yes mutable is a tool for experts - and I won't use a std library
> >implementation not written by an expert...
>
> Fine. But everyone, including experts, make mistakes. So we
> should stay away from dangerous language constructs as much
> as possible, and this includes staying away from 'mutable' as
> much as possible.
By that same logic, we should avoid classes with friends,
member variables that are pointers, any class with multiple
inheritance, standard containers and iterators, new-style
casts, and pretty much everything in C++ that isn't also
in C.
Oh, gosh, I'd like to go on, but I'm using my keyboard; it's
not actually a language construct, but it is dangerous, so
I'm trying to avoid it when possible.
I wonder if I can post this without using the dangerous mouse...
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/12 Raw View
On 12 Jan 99 06:49:18 GMT, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
>Yes. If an object is const, that means that it won't change during its
>lifetime. But constness says nothing about what the lifetime will be.
>It's quite legal to destroy or delete a pointer to a const object.
Changing the thread a little, I wish it were illegal to call delete,
delete[], or a destructor on a pointer-to-const. This would make
C++ a little safer as deleting an object is, by common sense, a way
of changing it. The rule should be if you want to do "delete x",
then 'x' should be a pointer-to-nonconst. This means that we may
have to use a const_cast to make the delete statement work. But
for stack objects, deletion is automatic and a const_cast should
not be required. I think this would be a nice change to C++.
> void f(const T *p1, const T *p2) {
> delete p1; // legal
> p2->~T(); // legal
> }
By the new rule, both lines above would be illegal. Of course,
if you have a non-const pointer to a T and T contains a const
data member by value, then the delete statement is well defined
and no const_cast is required. Eg,
struct T { const int t; explicit T(int t); }
int main() {
T * t=new T(1);
delete t;
// 't' is pointer to non-const, so this delete statement works
// T::t is a stack based object, so its deletion is automatic
// in short, this program is well defined
}
>References and iterators become invalidated when the lifetime of what
>they refer to ends. Constness doesn't provide any guarantees about
>lifetimes not ending.
Yes, basic_string::c_str() is a const member function, but calling
this const function may invalidate iterators pointing to chars
in the string. However, I don't think that your example of
"delete p1" above is good because I don't like the rule that you
can call 'delete' or a destructor on a const object.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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 ]
Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/12 Raw View
On 12 Jan 1999 06:41:18 GMT, AllanW@my-dejanews.com
> sbnaran@uiuc.edu wrote:
>> Fine. But everyone, including experts, make mistakes. So we
>> should stay away from dangerous language constructs as much
>> as possible, and this includes staying away from 'mutable' as
>> much as possible.
Note the "as much as possible". It is reasonable to use these
powerful features, as C++ supports them. But if it is possible,
and possible in a reasonably simple manner, then we should
prefer not to use these features. This is good design
guideline as it makes maintainance easier. It is not an
absolute guideline, hence the phrase "as much as".
>By that same logic, we should avoid classes with friends,
>member variables that are pointers, any class with multiple
>inheritance, standard containers and iterators, new-style
>casts, and pretty much everything in C++ that isn't also
>in C.
I guess you're being sarcastic, but I honestly agree with
some of what you've said. Except for one thing: change the
"avoid" to "try to avoid" as it is not an absolute design
guideline, but rather a strong one.
Yes, we should think twice about friendship, especially
long distance friendship. Member variables that are
pointers are ok (I like pointers, even though I never
learned C). Yes, think twice about multiple inheritance.
Standard containers and iterators are awesome. And
prefer new style casts to old style ones, but if possible,
try not to use casts at all.
>Oh, gosh, I'd like to go on, but I'm using my keyboard; it's
>not actually a language construct, but it is dangerous, so
>I'm trying to avoid it when possible.
>
>I wonder if I can post this without using the dangerous mouse...
Maybe you shouldn't read my reply ... it might hurt your eyes :)
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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 ]
Author: sirwillard@my-dejanews.com
Date: 1999/01/12 Raw View
In article <slrn79lsqb.o2q.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> On 12 Jan 99 06:49:18 GMT, Fergus Henderson <fjh@cs.mu.OZ.AU> wrote:
>
> >Yes. If an object is const, that means that it won't change during its
> >lifetime. But constness says nothing about what the lifetime will be.
> >It's quite legal to destroy or delete a pointer to a const object.
>
> Changing the thread a little, I wish it were illegal to call delete,
> delete[], or a destructor on a pointer-to-const. This would make
> C++ a little safer as deleting an object is, by common sense, a way
> of changing it.
No, I don't agree that that is common sense.
> The rule should be if you want to do "delete x",
> then 'x' should be a pointer-to-nonconst. This means that we may
> have to use a const_cast to make the delete statement work.
An awfully ugly hack just to prevent leaking memory, and it doesn't eliminate
the problem _you_ perceive with const.
> But
> for stack objects, deletion is automatic and a const_cast should
> not be required. I think this would be a nice change to C++.
So, destructors can be called on const objects implicitly but not explicitly.
Doesn't that strike you as a lot more confusing to programmers then the
current view that lifetime is not part of an objects state, and therefore not
affected by const?
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/05 Raw View
We note that class basic_string<Ch> has a member function c_str
that returns a pointer to the string as a Ch*. For Ch==char,
this means that we get a pointer to a null terminated string.
The problem with this is that the implementation is required to
store the string as a null terminated string -- so that there
is something for c_str to return. But other implementations,
other ways of storing the string, are possible, and two of
these are given below. So shouldn't c_str(),
ifstream(const char*), and so on be deprecated?
First, it is common to concatenate a string letter by letter,
as in "string+=ch1 ... string+=ch2 ...". If the string is
stored internally as a C style string, then each
concatenation involves adding two chars -- adding a ch1 or
ch2, and then adding a null char. But if the implementation
could store strings as non null-terminated strings, then each
char concatenation would add just one char.
An implementation could also store strings as an array of
sub-strings. This has the advantage of saving space if
there are lots of common substrings. I saw this idea
mentioned in Stroustrup's book, although it doesn't seem
very practical to me.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/05 Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
>We note that class basic_string<Ch> has a member function c_str
>that returns a pointer to the string as a Ch*. For Ch==char,
>this means that we get a pointer to a null terminated string.
>The problem with this is that the implementation is required to
>store the string as a null terminated string -- so that there
>is something for c_str to return. But other implementations,
>other ways of storing the string, are possible, ...
The standard requires that c_str return a null-terminated
byte string (NTBS) for strings based on char. It does not
specify how strings are stored internally.
The implementation can store a string however it likes. If the
storage method is not compatible with the requirements of c_str,
the c_str function can convert the internal representation
to an NTBS and return the NTBS.
Simple example: The string<char> implementation can store the data
as a char array that is not null-terminated. (The string keeps
track of the current length, and so doesn't need a null byte.) The
c_str function stores a null byte after the last valid character,
extending the string if there isn't room for the null. It then
returns the address of the char array.
--
Steve Clamage, stephen.clamage@sun.com
[ 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 ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/01/06 Raw View
Siemel Naran wrote:
>
> We note that class basic_string<Ch> has a member function c_str
> that returns a pointer to the string as a Ch*. For Ch==char,
> this means that we get a pointer to a null terminated string.
> The problem with this is that the implementation is required to
> store the string as a null terminated string -- so that there
> is something for c_str to return. But other implementations,
> other ways of storing the string, are possible, and two of
> these are given below. So shouldn't c_str(),
> ifstream(const char*), and so on be deprecated?
>
21.3.6/2: The program shall not alter any of the values stored in the
array. Nor shall the program treat the returned value as a valid pointer
value after any subsequent call to a non const member function of the
class basic_string that designates the same object as this.
That is, the representation as a null-terminated string can be separate
from the internal representation of the string.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
[ 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 ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/06 Raw View
In article <76u5kh$r6t$1@engnews2.Eng.Sun.COM>, Steve Clamage
<stephen.clamage@sun.com> writes
>Simple example: The string<char> implementation can store the data
>as a char array that is not null-terminated. (The string keeps
>track of the current length, and so doesn't need a null byte.) The
>c_str function stores a null byte after the last valid character,
>extending the string if there isn't room for the null. It then
>returns the address of the char array.
Could it not also use a mutable char * data member that initially was a
null pointer, but could point to a NTBS, created as needed when c_str()
was called? This would seem to meet the concept of not paying for what
you do not use.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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 ]
Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/01/06 Raw View
Siemel Naran<sbnaran@KILL.uiuc.edu> wrote:
>
>We note that class basic_string<Ch> has a member function c_str
>that returns a pointer to the string as a Ch*. For Ch==char,
>this means that we get a pointer to a null terminated string.
>The problem with this is that the implementation is required to
>store the string as a null terminated string -- so that there
>is something for c_str to return.
False. The implementation may generate the null-terminated
form when c_str() is called, and discard it the next time
the string is modified.
> But other implementations,
>other ways of storing the string, are possible, ...
True.
> So shouldn't c_str(),
>ifstream(const char*), and so on be deprecated?
No.
>But if the implementation
>could store strings as non null-terminated strings, then each
>char concatenation would add just one char.
True.
>An implementation could also store strings as an array of
>sub-strings. This has the advantage of saving space if
>there are lots of common substrings. I saw this idea
>mentioned in Stroustrup's book, although it doesn't seem
>very practical to me.
E.g. The SGI STL comes with a "Rope" which stores strings sort
of as a tree of substrings.
Unfortunately some time when I wasn't looking, the Library
Working Group sneaked in a change so that the expression
s[s.size()]
must return a null. (The same expression for _s_ a vector
is undefined, as it should be.) This means that either there
must really be a null there, or operator[]() must be jimmied
to fake it.
--
Nathan Myers
ncm@nospam.cantrip.org http://www.cantrip.org/
---
[ 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 ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/06 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
>In article <76u5kh$r6t$1@engnews2.Eng.Sun.COM>, Steve Clamage
><stephen.clamage@sun.com> writes
>>Simple example: The string<char> implementation can store the data
>>as a char array that is not null-terminated. (The string keeps
>>track of the current length, and so doesn't need a null byte.) The
>>c_str function stores a null byte after the last valid character,
>>extending the string if there isn't room for the null. It then
>>returns the address of the char array.
>Could it not also use a mutable char * data member that initially was a
>null pointer, but could point to a NTBS, created as needed when c_str()
>was called? This would seem to meet the concept of not paying for what
>you do not use.
Well, yes, but I think my simple example also meets that criterion.
It is reasonable to use a char array to store a string of chars.
The cost (if any) of adding the null byte is paid only when c_str
is called.
Your suggestion would be more appropriate when some different
representation for strings was used internally. In that case,
you would not want to maintain a parallel NTBS array all the
time, but create it only as neeeded.
--
Steve Clamage, stephen.clamage@sun.com
[ 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 ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/01/06 Raw View
In article <slrn794vfb.8hg.sbnaran@fermi.ceg.uiuc.edu>,
sbnaran@KILL.uiuc.edu wrote:
>
> We note that class basic_string<Ch> has a member function c_str
> that returns a pointer to the string as a Ch*. For Ch==char,
> this means that we get a pointer to a null terminated string.
> The problem with this is that the implementation is required to
> store the string as a null terminated string -- so that there
> is something for c_str to return.
No. It is only required to provide a null terminated string when c_str
is called.
> But other implementations,
> other ways of storing the string, are possible, and two of
> these are given below. So shouldn't c_str(),
> ifstream(const char*), and so on be deprecated?
>
> First, it is common to concatenate a string letter by letter,
> as in "string+=ch1 ... string+=ch2 ...". If the string is
> stored internally as a C style string, then each
> concatenation involves adding two chars -- adding a ch1 or
> ch2, and then adding a null char.
This would be ridiculous. My own implementation ensures that there is
always an extra byte free (the buffer size is 1 greater than capacity),
but it only appends the '\0' when c_str is called, and never otherwise.
I suspect that this is the general approach.
> But if the implementation
> could store strings as non null-terminated strings, then each
> char concatenation would add just one char.
>
> An implementation could also store strings as an array of
> sub-strings. This has the advantage of saving space if
> there are lots of common substrings. I saw this idea
> mentioned in Stroustrup's book, although it doesn't seem
> very practical to me.
It depends on what you are doing. Things like insertion in the middle
of a string are significantly faster in such an implementation. If you
visit the SGI site, look at their rope class, which does things this
way.
Of course, this means that the functions c_str and data are going to be
a bit slower, since it means that the string must change its
representation when they are called.
--
James Kanze GABI Software, S rl
Conseils en informatique orient objet --
-- Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ 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 ]
Author: AllanW@my-dejanews.com
Date: 1999/01/07 Raw View
In article <slrn794vfb.8hg.sbnaran@fermi.ceg.uiuc.edu>,
sbnaran@KILL.uiuc.edu wrote:
>
> We note that class basic_string<Ch> has a member function c_str
> that returns a pointer to the string as a Ch*. For Ch==char,
> this means that we get a pointer to a null terminated string.
> The problem with this is that the implementation is required to
> store the string as a null terminated string -- so that there
> is something for c_str to return.
The other choice is for c_str to add the null terminator before
returning. If the internal buffer does not already have enough
space for a null terminator, it must be expanded to make room.
Then, the buffer position one past the end of the string is set
to null, and the address is returned.
Later, when the string is changed, the implementation can ignore
the final null character. It can consider the character to be
allocated and initialized, but not part of the string. Thus, if
we add one more character to the string, it occupies the position
that was formerly set to null. (When the string is modified, the
application is not supposed to be using the c_str address anymore.)
> But other implementations,
> other ways of storing the string, are possible, and two of
> these are given below. So shouldn't c_str(),
> ifstream(const char*), and so on be deprecated?
I think it will be a long time before we can assume that most C++
programmers don't need to pass a C-style string to some other
function.
> First, it is common to concatenate a string letter by letter,
> as in "string+=ch1 ... string+=ch2 ...". If the string is
> stored internally as a C style string, then each
> concatenation involves adding two chars -- adding a ch1 or
> ch2, and then adding a null char. But if the implementation
> could store strings as non null-terminated strings, then each
> char concatenation would add just one char.
This still involves adding only one char. In the implementation
that you say is forced, there is already a null character which
is not considered to be part of the string. We change this null
character to be the newly-added char, and then we add one more
char -- the null byte.
Another possible implementation is to ignore the null char,
if it happens to be there. Add only the one character that was
added. If the user calls c_str() again, you make sure that the
char just beyond the string is null -- extending the string by
at least one char, if neccesary.
> An implementation could also store strings as an array of
> sub-strings. This has the advantage of saving space if
> there are lots of common substrings. I saw this idea
> mentioned in Stroustrup's book, although it doesn't seem
> very practical to me.
An implementation could do this up until the moment that the user
called c_str. At that time it would have to allocate an array of
Ch and copy all the characters plus a null byte. It could use this
array to replace the old data, or it could hang on to it until
such time as the string is changed.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ 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 ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/07 Raw View
On 07 Jan 99 03:27:02 GMT, AllanW@my-dejanews.com
>The other choice is for c_str to add the null terminator before
>returning. If the internal buffer does not already have enough
>space for a null terminator, it must be expanded to make room.
>Then, the buffer position one past the end of the string is set
>to null, and the address is returned.
I didn't think of the idea of adding a null char in the accessor
function basic_string::c_str(). In any case, it might not be
possible to expand the internal buffer when c_str is called;
string::operator+=(char) has to ensure that the internal buffer
has space for the null char, even if it hasn't bothered to put
the null char there. This is because expanding the buffer may
mean relocating it. But in the constant member function
string::c_str() const, the buffer has type "char *const", so
it can't be relocated. Unless it is mutable, but that may be
a messy choice.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ 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 ]
Author: "Martijn Lievaart" <nobody@orion.nl>
Date: 1999/01/07 Raw View
Siemel Naran wrote in message ...
>
>On 07 Jan 99 03:27:02 GMT, AllanW@my-dejanews.com
>
>>The other choice is for c_str to add the null terminator before
>>returning. If the internal buffer does not already have enough
>>space for a null terminator, it must be expanded to make room.
>>Then, the buffer position one past the end of the string is set
>>to null, and the address is returned.
>
>I didn't think of the idea of adding a null char in the accessor
>function basic_string::c_str(). In any case, it might not be
>possible to expand the internal buffer when c_str is called;
>string::operator+=(char) has to ensure that the internal buffer
>has space for the null char, even if it hasn't bothered to put
>the null char there. This is because expanding the buffer may
>mean relocating it. But in the constant member function
>string::c_str() const, the buffer has type "char *const", so
>it can't be relocated. Unless it is mutable, but that may be
>a messy choice.
>
It might be messy, but it is imho exactly what mutable is for. The messy
part is encapsulated and the user is presented with a nice consistent view
of the object. For the user, the object is const, it doesn't change by
calling c_str() in his view.
I think this is a good way of looking at it, but I'm not completely sure
myself. Any views?
Martijn
--
My email address is intentionally set to /dev/null
mail me at mlievaart at orion in nl
---
[ 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 ]