|
I do that all the time when I debug and test extreme cases which are hard to simulate using input. I wouldn't want to be caught forgetting about them though.
--
For proper viewing, take red pill now
|
|
|
|
|
This is bad practice unless the language automatically converts between variable types. If that is the case then you could essentially assign any value to the object if you aren't careful.
Brad
Australian
- Bradml on "MVP Status"
If this was posted in a programming board please rate my answer
|
|
|
|
|
innominate wrote: and just laughs:
No, I cringe
|
|
|
|
|
Recently, i was reworking some code. The library was used to read in sets of rules, and process other data based on those rules. Over time, this library had evolved such that there were two different methods of processing rules ("simple" rules required a different code path than "complex" rules), and four different file formats for the rule storage. So before working on the required changes, i first put some work into reducing (so far as possible) the redundant code. As part of this, i wrote a class to parse the various file formats and present their contents in a consistent manner:
class CRuleReader
{
public:
CRuleReader();
void Open(...);
bool NextRule();
...
long GetId() const;
LPCTSTR GetCondition() const;
LPCTSTR GetValue() const;
...
};
This worked quite well, except for one thing: it was very slow. The methods for accessing rule data needed a fair bit of time behind the scenes to parse out the required information, validate it, and present it in a consistent manner. Fortunately, there was a simple solution: cache the results of internal calculations, and re-use the cached results whenever possible. I quickly made this change, and was quite pleased with the results... However, since these const methods now needed to write to the internal cache data, I'd done something rather ugly in these methods:
const_cast<CRuleReader*>(this)->CacheValueId(LPCTSTR key, long id);
Unpleasant as it looked, it allowed me to keep the public face of the class clean - methods that logically modified state were non-const , methods that did not were const . All things considered, i was still reasonably happy with it.
Then, a few days later, i stumbled on some similar code, and at last realized, that in over a decade of using C++, i'd managed to either avoid or forget the mutable keyword...
----
It appears that everybody is under the impression that I approve of the documentation. You probably also blame Ken Burns for supporting slavery.
--Raymond Chen on MSDN
|
|
|
|
|
My experience says, that after you write lines like:
const_cast<CRuleReader*>(this)->CacheValueId(LPCTSTR key, long id); maintaining programmers sometimes stick needles into a doll with your face
-------------------------
Don't worry, be happy )
|
|
|
|
|
Heh.
To be fair, some of that mess is a copy-paste error.
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
Anyway, complex casts, attempts to gain write access from const methods - and everything that introduces side effects to a program - are a perfect method to make your customer hate you...
-------------------------
Don't worry, be happy )
|
|
|
|
|
Well, in this case, the side-effects are hidden: logically, the const methods act const , as they never modify data that can be seen from the outside. A nicer solution would have been to solve the performance issues by re-writing other components, but that would have greatly expanded the scope of this change. Another potential strategy would have been to pre-cache everything, but that would have improved the (unlikely) worst-case scenarios at the expense of the much more common scenarios.
That said, i still cringe whenever i see a const_cast (or C-cast used as a const_cast ), and am very happy i was able to remove them.
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
I remember having such a problem some time ago. I made it this way:
class Something
{
...
public:
void PreCacheSomething();
bool Calculate() const;
}; In the code:
someObject.PreCacheSomething();
someObject.Calculate(); If you mean it - say it.
-------------------------
Don't worry, be happy )
|
|
|
|
|
Dmitry Khudorozhkov wrote: someObject.PreCacheSomething();
someObject.Calculate();
Now you've changed the interface though. The caller needs to be aware of what, really, is an implementation detail. Not to mention, it just relocates the problem - the caller now needs a non-const reference to someObject , even though logically they only need const methods.
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
I just thought...
What about using another object for precaching, and passing this object to someObject?
void Calculate(CacheObject* cache) const
-------------------------
Don't worry, be happy )
|
|
|
|
|
That would work, and does address the second point i made (although it still complicates the interface). I often do something similar in ASP.NET apps, where using the app's cache object solves a lot of problems and allows me to keep caching policy for items together with the code that generates those items.
Another way would be to use global or static class data, though this brings with it a different set of problems and limitations.
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
Interface complication is the least of evils here, I think.
Shog9 wrote: global
That's the evil!
Shog9 wrote: static class data
I'd say no, unless class is a singleton.
-------------------------
Don't worry, be happy )
|
|
|
|
|
Dmitry Khudorozhkov wrote: I'd say no, unless class is a singleton.
As would i, unless:
- The class will never be used across threads (or is able to accept responsibility for synchronization). Or,
- The data will be initialized once, explicitly, and never actually modified by any instance methods (this is a variation on the "pre-cache everything" strategy, and comes in handy when i'm going to be creating / destroying lots of these objects.)
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
Then, a few days later, i stumbled on some similar code, and at last realized, that in over a decade of using C++, i'd managed to either avoid or forget the mutable keyword...
If it makes you feel any better, I've done the same! Thanks for telling me about mutable
Regards
- Roger
|
|
|
|
|
Shog9 wrote: that in over a decade of using C++, i'd managed to either avoid or forget the mutable keyword...
Whoa. Me too, until I just read your post. I had a very similar problem recently. I had a static instance of a derived class that ensured thread-safety via a boost::mutex . Unfortunately, if the derived class would attempt to lock this mutex, I couldn't make the bloody function doing it const so I used a nasty hack similar to yours. I will now go back and look at mutable forthwith.
There is a good overview of this on the C++ FAQ:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.13[^]
|
|
|
|
|
Rob Caldecott wrote: There is a good overview of this on the C++ FAQ:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.13[^]
Heh... sure 'nuff.
----
...the wind blows over it and it is gone, and its place remembers it no more...
|
|
|
|
|
When I started at my current company I was given a c# / oracle project and asked to rewrite it from scratch. I was told the guy who wrote it had been fired and everyone who had attempted to maintain the code had given up. I reakon I could have provided six months of content for the WTF web site from this single project. By far my favorite part was how he returned values from oracle stored procs to the application.
Every stored proc returned a var of type VARCHAR2_32_ARRAY, and looked something like this
CURSOR CUR_PARAMETERS IS
SELECT
CAST (
MULTISET (
SELECT
COLUMN_NAME_1 || ':' || COLUMN_NAME_2 || ':' || COLUMN_NAME_3
FROM
SOME_TABLE_NAME
WHERE
SOME_FIELD = SOME_VAL
) AS VARCHAR2_32_ARRAY
)
FROM
DUAL;
RESULT_VAR VARCHAR2_32_ARRAY;
BEGIN
OPEN CUR_PARAMETERS;
FETCH CUR_PARAMETERS INTO RESULT_VAR;
CLOSE CUR_PARAMETERS;
RETURN RESULT_VAR;
END;
then in the c# code we had things like this
private void ParseResults ( IDataReader p_reader)
{
while ( p_reader.Read () )
{
string _encoded_record = ( string ) p_reader [ 0 ];
string[] _fields = _encoded_record.Split ( new char[] {':' } );
double var1 = Double.Parse( _fields [ 0 ] );
etc etc etc
}
}
Interesting way of doing things to say the least
System.IO.Path.IsPathRooted() does not behave as I would expect
|
|
|
|
|
Old habits die hard.
It reminds me of:
At a job I had ten years ago, we were just switching from Oracle using PRO*C to Sql Server (6 I think) using ODBC. No one in the company knew anything about ODBC so a "consultant" was brought in and, as the story went, given two days to write us a library of functions we could use.
What he did, as the story continued, was copy examples from the floppy that came with an ODBC book. The functions returned the values as CSV strings! Management thought this was a perfectly usable solution.
When I started using it after others had been for six months or so I said something that can't be repeated in the Lounge. There was absolutely no way I was going to stand for it, but I didn't have much time to fix it, so I made it only marginally better... my versions of the functions returned the values as arrays of strings.
I left the company soon after, but had I stayed I was to be tasked with completely rewriting the library, I wish I had.
--| "Every tool is a hammer." |--
|
|
|
|
|
Just got a message box after the USER ID and password validation module took my inputs.
"You cannot have this password because USER ID 34C has chosen this password"
While porting a very old VB app to C++
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
If that was a real error message then that is one of the funniest things I've seen in software.
Brad
Australian
- Christian Graus on "Best books for VBscript"
A big thick one, so you can whack yourself on the head with it.
|
|
|
|
|
It is real and this VB app was written by a group of three college students some 2 years back. The company now wants our team to port it to C++. The app has an interface to manipulate database that stores information related to point of sale products. This list has to be frequently updated and so was the app designed. Various levels of users will have access to various functionalities in it.
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
Be sure you keep the original message when upgrading, it is a very useful .
Regards,
Thomas Stockwell
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
Visit my homepage Oracle Studios[ ^]
|
|
|
|
|
Fantastic. Like the system I'm now working on, where the User table holds Password in plain text.
Only worse.
Superb.
|
|
|
|
|
You mean they forgot to include the user's full name, date of birth and CC number(s) in the message?
That's just sloppy.
|
|
|
|