walsh@dude.epps.kodak.com (Joe Walsh) (08/25/90)
I have a question about the use of const in member functions. It seems to me taht there are three different uses for const in member functions. They are: 1) constant arguments to the function A::f(const x) 2) constant return type from the function const char* A::g() 3) constant function where the object or 'this' is a constant. The second and third types seems to confuse me. Are there really two distinct types, and what is the syntax. I have seen int A::f() const; in some code as well as int const A::f(); and I am not sure if there is a diference. The former syntax does not seem to be accepted by g++. any help would be appreciated, thanks -- Joe Walsh Atex Publishing Systems 165 Lexington Road, 400/165L Billerica MA 01821 Internet: <walsh@epps.kodak.com> Usenet: <walsh@atexnet.uucp> Voice: 508-670-4022 Fax: 508-670-4033
sarima@tdatirv.UUCP (Stanley Friesen) (08/29/90)
[I tried to mail this, but it bounced, so here it is] In article <5027@atexnet.UUCP> you write: >I have a question about the use of const in member functions. It seems to me taht there are three different uses for const in member functions. They are: > >1) constant arguments to the function A::f(const x) >2) constant return type from the function const char* A::g() >3) constant function where the object or 'this' is a constant. > >The second and third types seems to confuse me. Are there really two distinct >types, and what is the syntax. Yes, and in fact #3 is more closely related to #1 than #2 (since the object is passed as hidden extra argument in most implementations). Case #2 is used where the function returns some private data that should not be modified by the caller. Case #3 is used where the member function should not be allowed to modify the state of the object it is invoked on. > >I have seen > >int A::f() const; in some code as well as int const A::f(); and I am not sure >if there is a diference. The former syntax does not seem to be accepted by g++. You seem to have an old version of g++. The former syntax is new to cfront version 2.0, and its equivalents from other vendors. (The latest g++ does in fact accept it, I believe). int A::f() const; declares a 'constant function' where 'this' is constant. int const A::f(); is the same as: const int A::f(); and declares a function returning a constant result, which is only meaningful if the function returns a pointer or a reference.
vaughan@puma.cad.mcc.com (Paul Vaughan) (09/05/90)
Awhile back I posted a message asking if const was really worth the trouble. Everyone who replied either on the net or privately thought that making a program const correct was indeed worth the effort. These were all pretty subjective opinions--it's kind of hard to measure how much difference it makes. So, here's a const question. Consider the following function const char* substring(const char* string, const char* sub) // substring searches for the first occurence of sub in string and //returns a pointer to it or 0 if none is found. { ....} If I'm working on a const char* (and, therefore, don't plan on changing any part of it) this works just fine. However, if I'm working on a char* and was planning to change part of it and was using substring to find that part, this will cause a problem because substring returns a const. For example, char* foo = "barfoobar"; *substring(foo,"foo") = `\0`; will give an error due to the modification of a non-const return value. I can't declare substring as char* substring(const char* string, const char* sub) because it is returning a pointer to part of the string that is passed in. I would declare it char* substring(char* string, const char* sub) but then I can't use it to deal with const char*'s, and, of course, I can't overload it based on the return type! So what do I do? My solution so far has been to declare it const char* substring(const char* string, const char* sub) and when I want to work on a char*, I do a cast, like this char* foo; char* bar = (char*) substring(foo, "foo"); Given the semantics of the function and that I'm passing in a char*, I can verify the safety of the cast without much trouble. Is there a better way? Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639 Box 200195, Austin, TX 78720 | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan
sarima@tdatirv.UUCP (Stanley Friesen) (09/05/90)
In article <10863@cadillac.CAD.MCC.COM> vaughan@puma.cad.mcc.com (Paul Vaughan) writes: >Consider the following function >const char* substring(const char* string, const char* sub) >// substring searches for the first occurence of sub in string and >//returns a pointer to it or 0 if none is found. >{ ....} > >If I'm working on a const char* (and, therefore, don't plan on changing >any part of it) this works just fine. However, if I'm working on a >char* and was planning to change part of it and was using substring to >find that part, this will cause a problem because substring returns a >const. ... >I can't declare substring as >char* substring(const char* string, const char* sub) >because it is returning a pointer to part of the string that is passed >in. I would declare it > >char* substring(char* string, const char* sub) > >but then I can't use it to deal with const char*'s, and, of course, I can't >overload it based on the return type! But I believe you *can* overload it on the type of the first argument based on the presence/absence of 'const'. In other words, declare it *both* the first and the second way. This will then call either the const or non-const version depending on whether the first argument is a const string or not. --------------------------------- uunet!tdatirv!sarima (Stanley Friesen) -L -I -N -E - -C -N -T
twagner@baobab.berkeley.edu (Tim Wagner) (09/06/90)
In article <10863@cadillac.CAD.MCC.COM>, vaughan@puma.cad.mcc.com (Paul Vaughan) writes: |> |> Awhile back I posted a message asking if const was really worth the |> trouble. Everyone who replied either on the net or privately thought |> that making a program const correct was indeed worth the effort. |> These were all pretty subjective opinions--it's kind of hard to |> measure how much difference it makes. |> |> So, here's a const question. |> [deleted] This points out once again the problems inherent in C's (and therefore C++'s) use of 'const'. The return type of the function is not a good mechanism in this case: obviously, one cannot really alter the returned value anyhow, so calling it 'const' is redundant. However, the context in which that returned value is used should be controlled; that is, an lvalue getting such a returned object should be const itself. That brings us to the problem of "really constant" versus "sometimes contstant" which has already been beaten to death (by me and others--see back issues for more). In other words, you're right; it's ugly and broken. Tim Wagner twagner@sequoia.Berkeley.EDU
ark@alice.UUCP (Andrew Koenig) (09/07/90)
In article <27503@pasteur.Berkeley.EDU>, twagner@baobab.berkeley.edu (Tim Wagner) writes: > This points out once again the problems inherent in C's (and therefore C++'s) > use of 'const'. The return type of the function is not a good mechanism > in this case: obviously, one cannot really alter the returned value anyhow, > so calling it 'const' is redundant. However, the context in which that > returned value is used should be controlled; that is, an lvalue getting > such a returned object should be const itself. Not at all! If you assign the result of a function to a variable, the variable gets a copy of that result. Just because the result itself is a constant, that doesn't say anything about the copy. For example: int x = 3; Here, 3 is a `const int,' but that surely does not oblige x to be a const! Similarly: extern const int f(); main() { int x = f(); // ... } Again, there is no particular reason why x should have to be a const. -- --Andrew Koenig ark@europa.att.com
davidm@uunet.UU.NET (David S. Masterson) (09/07/90)
In article <142@tdatirv.UUCP> sarima@tdatirv.UUCP (Stanley Friesen) writes:
But I believe you *can* overload it on the type of the first argument based
on the presence/absence of 'const'. In other words, declare it *both* the
first and the second way. This will then call either the const or
non-const version depending on whether the first argument is a const string
or not.
The point is that:
const char* substring(const char*, ...)
// first argument is important for this discussion
has a very unuseful return value (because its a constant). Changing it to:
char* substring(char*, ...)
makes the return value useful again, but removes the hint about what might be
optimized by the compiler (like whether its valid to place the arguments or
returns in registers). Note also that for the substring() function:
char* substring(const char*, ...)
is not possible (in this argument) because of the definition that "once a
const, always a const" (the return value will be a pointer to something in the
argument, therefore, its a const char*). Because of that definition,
overloading these last two is not possible.
The point is that in this example, you would like to use CONST on the argument
in order to make it plain that the function will not be changing the argument
(which provides optimization information for the function). However, you
don't want to use CONST on the return value because it is likely that the user
of the function will want to change the substring once substring() found it.
But, by definition of "once a const, always a const", this does not seem to be
possible.
--
====================================================================
David Masterson Consilium, Inc.
uunet!cimshop!davidm Mtn. View, CA 94043
====================================================================
"If someone thinks they know what I said, then I didn't say it!"
ark@alice.UUCP (Andrew Koenig) (09/07/90)
In article <CIMSHOP!DAVIDM.90Sep6181221@uunet.UU.NET>, cimshop!davidm@uunet.UU.NET (David S. Masterson) writes: > The point is that: > const char* substring(const char*, ...) > // first argument is important for this discussion > has a very unuseful return value (because its a constant). But if substring returns a pointer into the first argument, then the return value had better be const! > Changing it to: > char* substring(char*, ...) > makes the return value useful again, but removes the hint about what might be > optimized by the compiler (like whether its valid to place the arguments or > returns in registers). Note also that for the substring() function: > char* substring(const char*, ...) > is not possible (in this argument) because of the definition that "once a > const, always a const" (the return value will be a pointer to something in the > argument, therefore, its a const char*). Because of that definition, > overloading these last two is not possible. But the following is most certainly possible: const char* substring(const char*, const char*); char* substring(char*, const char*); and as far as I can see, it will do exactly the right thing. > The point is that in this example, you would like to use CONST on the argument > in order to make it plain that the function will not be changing the argument > (which provides optimization information for the function). However, you > don't want to use CONST on the return value because it is likely that the user > of the function will want to change the substring once substring() found it. If the argument is memory that can't be changed, and the return value is part of the argument, then the return valud had better be immutable as well. I should point out, though, that if you have a pointer to mutable memory and you convert that pointer to a pointer to const, it is entirely legitimate to cast it back. Therefore, there's no reason not to write the following: extern const char* substring(const char*, const char*); inline char* substring(char* p, const char* q) { return (char*) substring((const char*) p, q); } At first glance, one might think it unnecessary to cast p to const char*, but one would be wrong: without the cast, the result would be a recursion loop. Think about it. -- --Andrew Koenig ark@europa.att.com
mat@mole-end.UUCP (Mark A Terribile) (09/08/90)
In article <10863@cadillac.CAD.MCC.COM>, vaughan@puma.cad.mcc.com (Paul Vaughan) writes: . . . > So, here's a const question. . . . > Consider the following function . . . > const char* substring(const char* string, const char* sub) > // substring searches for the first occurence of sub in string and > //returns a pointer to it or 0 if none is found. . . . > [But what if I want to operate on non-const characters??] Yup, you've got a real problem, though not an insurmountable one. Starting with Release 2.0, you should be able to overload on const/non-const-ness . You can't do it on the basis of the return type, but you can do it on the basis of the first string. const char* substring( const char* string, const char* sub ); char* substring( char* string, const char* sub ); Does this mean that you have to implement it twice (ignoring that the first substring() may already exist elsewheres)? Weeeeeelllll ... I don't think it unreasonable to write inline char* substring( char* string, const char* sub ) { return (char*) substring( (const char*) string, sub ); } There are some places where this sort of thing won't work; you really need different algorithms. It would be nice to be able to say that a function's return type is const if certain actual arguments are const. This is probably not something we will see soon, except perhaps in templates. Unfortunately, when you use templates, it is expected (last time I checked) that a weaker form of argument matching will be applied than for ordinary functions. -- (This man's opinions are his own.) From mole-end Mark Terribile
davidm@uunet.UU.NET (David S. Masterson) (09/10/90)
In article <11306@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: > > If the argument is memory that can't be changed, and the return value > is part of the argument, then the return value had better be immutable > as well. > > I should point out, though, that if you have a pointer to mutable > memory and you convert that pointer to a pointer to const, it is > entirely legitimate to cast it back. Exactly the point of the substring() example. I guess the question here is can the compiler know and keep track of the differences between a pointer to mutable memory and a pointer to immutable memory if both are declared as "const char*"? > Therefore, there's no reason not > to write the following: > > extern const char* substring(const char*, const char*); > inline char* substring(char* p, const char* q) { > return (char*) substring((const char*) p, q); > } > > At first glance, one might think it unnecessary to cast p to > const char*, but one would be wrong: without the cast, the > result would be a recursion loop. Think about it. Obviously, the cast of p is necessary to prevent recursion, but isn't the cast of the return value of substring() a violation of the idea that "once a const, always a const" (which, I thought, was the point of the discussion)? How can the compiler know that the result of: extern const char* substring(const char*, const char*); is mutable because it is a direct result of the p (which is mutable, but casted to const)? It would seem that this could only be known in a separate compilation step. As far as this compilation step is concerned, this substring could work in a couple of ways -- return a pointer into the first argument or copy the first argument to someplace truly read-only and return a pointer to that. The compiler can't know, can it? -- ==================================================================== David Masterson Consilium, Inc. uunet!cimshop!davidm Mtn. View, CA 94043 ==================================================================== "If someone thinks they know what I said, then I didn't say it!"