Article View: comp.std.c++
Article #3807Re: constness of private members and methods
From: Rob Stewart
Date: Tue, 26 Mar 1996 06:55
Date: Tue, 26 Mar 1996 06:55
116 lines
6494 bytes
6494 bytes
Philippe Verdy wrote: > > Many recursive data structures require algorithms to handle > them which have to mark and unmark all scanned objects in > order to avoid infinite recursion when walking on that > structure, or when building items iterator. > Such algorithms will use the mark() and unmark() private > methods in each visited node, so that we can detect paths > which have already been visited. his is critical for example > when managing with auto-references, graphs, dictionnaries > of polymorphic objects (containing dictionnaries like in > a PostScript interpret). > However, how can we apply standard read-only methods on such > objects: these methods are specified as const in one of the > base classes, and virtual override requires not to change the > constness of the derived object. > So we cannot mark such structures, because even a private > member cannot be modified in a const instance. > We can effectively change temporarily the constness of the > object to realize this mark, but in that case we would write > the following :[snip] > The problem is that now mark() and unmark() methods are not > const so they cannot be used in read-only methods like show(). > So we have to use a const_cast<T&> or const_cast<T*> to > suppress this constness. > > This is not obvious, and has the big disadvantage of globally > suppressing the constness of the object. So this is quite > dangerous, because some-times, we do not know really if a > method has an impact on the semantic value of the instance > on which we apply this cast. So this is a security hole which > should be avoided. > > We can avoid const_casting to call mark() and unmark() by > declaring them as const, like this:[snip] > but this is really hard to write, and is it semantically > correct ? It would from the public point of view, but what > on the private point of view ? > > We can also use explicitly (const_cast<T*>this)->mark(); and > (const_cast<T*>this)->unmark(); calls in the show() > implementation, but this is quite hard to write, so that many > users refrain using const specifiers on their classes. > [snip] > What do you think ? > > And is constness definition a semantic only definition, > or does it involve a more strict sense in which the compiler > optimizer would have an influence (such as in common > subexpressions reduction) ? There are two schools of thought regarding const-ness. One requires strict bitwise constness. That means that if you construct a const object, did a memcpy of the object to some suitable buffer, exercised the object using any permissible (const) mfs, in any combination, then compared the object with the memcpy'd buffer, there would be no change. The other requires only logical constness. That means that the object always appears the same through its public and protected interfaces. You can do what you want inside the object, provided it always appears the same to the class user. The compiler obviously enforces the former definition. You must cast away constness when you want the latter. That definition is the one you're employing here. According to how you've described mark and unmark, they must be controlled by other functions such that the original state is restored before return to the caller. That is, some other function must use mark and unmark, in matched sets for each node, in order to preserve the external state of the object. Therefore, it is not mark and unmark which should cast away constness, but those functions that make use of them. mark and unmark should be non-const; they each change the state in a way that affects the external state of the class. Those functions calling them must cast away constness to use them. As for your question about some language extension to permit that behavior, it could only apply to functions calling mark and unmark in their use of them. That is, since only functions using mark and unmark can ensure that the original state is restored--thus preserving the logical constness--only they can be used on const objects. Therefore, they should be the ones to get special dispensation to use non-const mfs in such a way that they retain logical constness. The difficulty is with maintenance. Sure, after some design and debugging work, you can get the functions to work correctly such that you retain logical constness. The maintainer of your code may have more trouble or may not realize the consequence of his actions, and destroy logical constness. Once you violate the bitwise constness of the compiler, you're on your own. This is true of casting away constness yourself, but would we really want a language feature which makes it easy and makes less clear where special attention is required? I don't think so. Instead, you should consider how to build a base class that encapsulates the iteration process to which you can pass a derived class mf to process each node you encounter. The implementation will appear once in your code and shouldn't require maintenance once you fix the bugs. All the rest of your code that needs to iterate the container will make use of that base class functionality, but won't need to worry about casting away constness. -- Robert Stewart | My opinions are usually my own. Datalytics, Inc. | stew@datalytics.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 ] [ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ] [ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ] [ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Technical Details
Message-ID:
<31570972.3230@datalytics.com>Path:
arc1-ca.pugleaf.net!cs.mu.OZ.AU!bounce-backReferences:
<4j49e0$8fo@dub-news-svc-4.compuserve.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!cs.mu.OZ.AU!bounce-back From: Rob Stewart <stew@datalytics.com> Newsgroups: comp.std.c++ Subject: Re: constness of private members and methods Date: 26 Mar 96 06:55:16 GMT Organization: Datalytics, Inc Approved: fjh@cs.mu.oz.au Message-ID: <31570972.3230@datalytics.com> References: <4j49e0$8fo@dub-news-svc-4.compuserve.com> NNTP-Posting-Host: munta.cs.mu.oz.au X-Original-Date: Mon, 25 Mar 1996 16:00:34 -0500 X-Mailer: Mozilla 2.0 (WinNT; I) X-Auth: PGPMoose V1.1 PGP comp.std.c++ iQBFAgUBMVeU/uEDnX0m9pzZAQFByAF/cSlCWypHS7yTkSXLfkHF3qZkQhxou8oc owytKt9kwyq8JYQK3Hb4SD2GYcEM8WXz =O63S Originator: fjh@munta.cs.mu.OZ.AU