Thursday, August 16, 2012
Tuesday, April 27, 2010
There seems to be a relative dearth of C++ related blogs out there, at least compared to the webby world of Java and Ruby and the like. One that I have found to be consistently good is The C++ Reference Guide, though it is debatable if it can really be considered a blog. As the name implies it's a reference guide for C++, but as it is in the process of being created it has a RSS feed that gets updated as new topics are added. There's also a bit more commentary in it than one would normally expect from a reference guide. Given these two qualities I'm considering it a blog, even if that's not strictly accurate.
Now while I did say that the Guide is consistently good, I do find fault with it from time to time. The most recent case would be the following:
Declaring value arguments as const is a close relative of the first gaffe. Raise your hand if you haven't seen a hyper-corrective (yet utterly wrong) function declaration of this kind:
void doStuff(const int action_code);
Programmers who declare a value argument as const don't realize that by doing so, they expose themselves to mockery. Even if their aim is to document the fact that the function isn't allowed to modify its argument, declaring a value argument const is redundant and wrong. Remember: the const in this context applies to a local copy of the argument passed to the callee. It doesn't apply to the caller's argument. Hence, declaring value arguments as const is always a bad idea.
Bottom line: never declare value arguments as const. Although it might seem harmless, it's plain wrong, and it might suggest that you don't understand the C++ argument passing mechanism at all.
Let me start by saying that I declare const by value arguments all the time when the type being passed is a primitive like int1. Now I'm pretty sure I have a decent grasp of what it means to pass a parameter by value; I understand that when a function takes a parameter by value it is making a copy of that value for its own internal use and thus the const doesn't affect the caller's variable in any way.
So why do it? That's none of your business, at least if you're the caller of my function. If my function takes a parameter by value then I have my own copy of the value that you passed in and I can do damn well anything I please with it including declaring it const. In this case the const is not for the caller's benefit, it's for the function author's. In my experience the more stuff you can declare const the better (stuff that can't change has less chance of being stuff that can break). The only way to make that parameter value const is to declare it as such in the function's declaration. This could probably be considered a leak of information about the function's internals by the interface, but it seems like a rather innocuous one to me. Maybe I should be demanding that the C++ standard be amended so that I can have my const by value arguments without having to declare them as such in function declarations so as to avoid ridicule and mockery by the likes of the author above...
Note that I do not do this with anything that is not a primitive type, I'm not a moron (as far as I know, the Dunning-Kruger effect notwithstanding). Unfortunately the code base that I work on passed through some less than stellar hands in the past and I see lots of functions that take arguments like const CString foo (note the lack of ampersand). ↩
Monday, December 14, 2009
This message has not been sent. WTF Outlook? I know that the message has not been sent -- I'm still writing it! Your endless little interruptions are growing tiresome. Like a four-year-old who's not getting enough attention you used to bug me about every little message that you got for me. Look at me, I've got a message that, no matter what, must be more important than whatever it is that you're working on. I finally broke you of that habit but now you have to bug me with your little comments about the obvious at the top of the window so that the rest of the window shifts and distracts me from the whole reason that I have your window open in the first place. Really, it just needs to stop. Plus, half the time your messages are premature; you declare messages as being replied to before I even finish writing the reply. And while we're talking, what have you done to piss off Windows? You seem to be the only program that Windows decides to aggressively swap, to the point that every time I try to raise your window I'm greeted with ten seconds of hard-drive grinding before I can use you. What are you doing to antagonize Windows so? Thunderbird doesn't have this problem. Maybe the sysadmin would be willing to turn on the IMAP support in the exchange server...
Friday, February 13, 2009
About once a year I end up thinking that using
boost::enable_shared_from_this is a good idea. And every time it ends up wasting almost an hour of my time. You see there's a restriction on
shared_from_this that disallows its use in the constructor of the object that is being shared from this. Unfortunately this restriction is not mentioned in the documentation. I always try to use
shared_from_this from the constructor and get bad weak pointer errors at run time. I then spend twenty minutes flailing around in the source code trying to figure out what I'm doing wrong until finally a bit of googling brings the not in the constructor restriction out in the open. Once I realize this and start trying to fix things so I don't need to use
shared_from_this in the constructor I find that I don't need
enable_shared_from_this at all. This happens every time. I'm guessing that most of the boost folks have had the same experience as well since they don't go out of their way to call attention to
enable_shared_from_this. Maybe I should stay away from libraries whose documentation can only be reached from a link in an answer to a FAQ about another library. That is just not a good sign.
boost::enable_shared_from_thisturned out to be useful.
Monday, September 8, 2008
In the process of hacking some C# compatibility into my Emacs config I came across this page. The page itself is moderately interesting and another entry in the guys blog held the solution to a problem I was facing. But the thing that jumped out at me were some of the comments. The most egregious was
You are so lame man... you spent all that time just so you have MOST of the features you get for free on the C# express. lol you FAIL at seeing the big picture
Yes, there are features in Visual Studio that Emacs lacks. I'll give him that. But then Visual Studio lacks the quality that Emacs has. The problem is to get at this quality you can't have this poster's attitude:
The problem is that while emacs and vim will always be flexible, they >require a lot of knowledge, time etc... to gather stuff.
And while you may know and enjoy writing elisp code, I simply refuse >to learn something specifically for one program. I could live with >python or ruby these days, or with a human-readable nice and easy >special language, but learning lisp just so that i maximize using >emacs sounds like sure overkill, especially cuz i would know i >wouldnt really use lisp outside from that (sorry lispers)
The power of Emacs comes from Elisp1. This is similar to the problem with this comment (and a few others like it)
Hey you do know that their is an Emacs mode inside of VS 2005 and >higher; just go to Tools ->Options-> Enviroment->Keyboard and select >Emacs.
It's not the keyboard shortcuts that make people use Emacs. It's the control that Elisp gives you. And I don't just mean writing huge amounts of code that implement huge features like JDEE2. It's little things. Like today I needed to insert a new function into a COM interface and then shift the id numbers of all the following functions up one. I could have just gone through and typed all the numbers but instead I just had to do a regex replace from "id(([0-9]+))" to "id(\,(+ 1 (string-to-number \1)))" and boom it was done in a split second. A lot less time, including that spent writing the regex, and way less brain numbing. And that's a pretty minor example, once you get the hang of it you start automating all sorts of little things that bug you that are too specific to be something the MS, Jetbrains or the Eclipse folks are going to bother dealing with. And, at least in my experience with Visual Studio, adding thee features to the IDE would be more pain then it is worth.
Maybe the best way to put it is: do you control what your tool can do or does your tool control what you can do? 3
Though it's funny, if the poster actually went out and learned a proper lisp like scheme or CL then the complaint would be coming form the opposite direction given the craptastic dialect that Elisp is. ↩
Though I bet it's a lot less code than you'd write in VBScript or whatever it is that Visual Studio is using these days. ↩
Insert Beavis and Butthead snickering here if you are so inclined. ↩
Wednesday, May 7, 2008
So I've come up with a new reason that C++'s lack of garbage collection is problematic. The strange thing is that the reason is in one of C++'s usual sweet spots: performance.
Really I should qualify the previous statement, I'm talking about performance in multi-threaded programs where you actually want your software to work in some sane fashion as opposed to just flailing around and crashing. In order to accomplish this you need to be making liberal use of
boost::shared_ptr or something similar in order to avoid having the rug pulled out from under you on a regular basis1.
Turns out that the
shared_ptr has a dirty little secret: copying one in a multi-threaded program is orders of magnitude slower than copying a bare pointer. The reason for this is that the
shared_ptr has a reference count in it. When you copy the
shared_ptr that reference count needs to be incremented in a thread-safe manner. On platforms that support it this is done using atomic integer operations, otherwise OS synchronization primitives come into play. Either way you're talking a lot more cycles than just a pointer copy since at minimum you need to wait for the atomic operations to maintain some semblance of processor cache sanity.
So does this mean that we abandon
shared_ptr in multi-threaded programs? In C++ the alternative (bare pointers) is much, much worse so I would say no.
Now if we had a modern2 garbage collected system we wouldn't need to sacrifice cycles to the cache sanity gods. Instead we could copy pointers to our hearts content. Occasionally we would need to give the garbage man some cycles so in a way the garbage collector is amortizing the cycles we need to spend on memory management. But if well implemented this is a much lower tax to pay. In extreme circumstances you could even take control of the collector and only allow it to run when it's not going to get in the way of more important things.
So how do we mitigate things? One option would be to hook up the Boehm garbage collector to our programs. At some point I'm going to sit down and benchmark the collector versus
boost::shared_ptr. But that might not be an option depending on how much legacy code we're talking about.
If you're stuck with no garbage collection then the thing to do is minimize how often a
shared_ptr is being copied. In the vast majority of cases you should take a const reference to a
shared_ptr as parameters. Unless you're doing something wrong then somewhere either on the stack or shudder in a global variable3 there is an instance of the
shared_ptr so you shouldn't have to worry about losing the object pointed at while your function is running. The exception to this is when passing the
shared_ptr to another thread. In that case you will need to create a copy of the
shared_ptr for the other thread. Note that taking a const reference saves you from a double-whammy. If you take the pointer by value then you pay for the new
shared_ptr instance when the function is called and again when the
shared_ptr instance is destroyed as the function exits.
You should also prefer plain old
dynamic_pointer_cast. The latter will increment the reference count on the pointer being casted. If you have the original
shared_ptr then you know the object being pointed at isn't going away so just cast the underlying pointer. Obviously if you are going to store the pointer away some where you'll have to pay for the copy.
Another thing to watch out for is locking
boost::weak_ptr. You pay every time since the reference count will be locked. If you are by chance using the pointer value without using the pointed to object all the time then consider storing the bare pointer along with the weak_pointer. Then you can use the pointer value whenever without paying to lock but still have the object lifetime monitoring of
weak_ptr when you need it.
boost::shared_ptr is great but be aware that it's use isn't free. And while it isn't free the alternative is worse, as long as we're not referring to real garbage collection, which is better.