Rants on software, computing, and any other topic I feel like.

Friday, May 06, 2011

Using malloc Safely in C++

For many of us C++ programmers, a key advantage of using the language is the compatibility with C. For the most part, this interface works well. However, there are some places where this interface isn't so easy to deal with. Take memory allocation for example. In C, one typically uses malloc (or some equivalent for the platform) to allocate memory and free to release it. In C++, we tend to use the built-in new and delete operators to accomplish the same thing.

When interacting with C libraries, it can sometimes be impossible to avoid using malloc and free. Libraries often assume that any memory that it allocates and hands off to the user will be freed using free. Since you can't tell what sort of memory a particular pointer points to, it's easy to make mistakes when deallocating them. Using mismatched allocators/deallocators might cause memory leaks, crash your program and work just fine depending the platform, compiler, or phases of the moon.

The first thought that any self respecting C++ programmer will think of is RAII (Resource Acquisition Is Initialization). So they might write a class that automatically calls free when the pointer is no longer needed.
template<typename T>
class malloc_handler
{
public:
malloc_handler() : _ptr(malloc(sizeof(T))) {}
~malloc_handler() { free(_ptr); }
T* ptr() { return _ptr; }
private:
T* _ptr;
};

void foo()
{
malloc_handler<int> x();
x.ptr();
}
This has a number of disadvantages including the lack of a copy constructor, the requirement of a new class and the lack of any convenient operator overloads to make it look more like a pointer. There's a much better way and one that doesn't require the programmer to roll their own solution. Use shared_ptr and its customer deleter feature.
shared_ptr<int> x((int*)malloc(sizeof(int)), free);
This feature is probably something that the creators of shared_ptr already envisioned, but I don't generally see it discussed. Now, the above code is a bit ugly, so we can make it a little bit easier by rolling our own code.
template<typename T>
shared_ptr<T> shared_malloc()
{
shared_ptr<T> rval((T*)malloc(sizeof(T)), free);
return rval;
}

shared_ptr<int> x = shared_malloc<int>();
We can create a safe version of strdup:
shared_ptr<char> shared_strdup(const char* str)
{
shared_ptr<char> rval(strdup(str), free);
return rval;
}

shared_ptr<char> s = shared_strdup("Hello World!\n");

Labels: , ,

Thursday, February 17, 2011

Calling a constructor or destructor without an object

Now, I have no idea why you'd actually want to call constructors or destructors without an object, since they're really normally meant to be called with objects, but it's something interesting I thought I'd share. It turns out that constructors and destructors aren't really that special in C++. They're just regular functions like almost anything else and can be called that way. You just need to know how to do it.

I'll start with destructors, which may seem backwards, but doing this with destructors is actually easier than with constructors. It's not that much easier, but it makes a bit more sense. Let's start by calling a destructor with an object. We'll get to the no-object case next.

To call a destructor if you have an object, well, just call it:


struct A {
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
};

void main()
{
A a;
a.~a(); // just call it like anything else
}


So how do we do this without an object? We need to think about what happens when any member function is called. When the compiler compiles a member function call, all it does differently from a normal function call is to add a pointer to the object as an extra parameter (at the begining) and call the function normally. Now certain compilers even use a different calling convention, but in the end, it's just a modified function call.

So can we get the compiler to make that function call, but not require a real object to pass in? Of course:


A* a = NULL;
a->~a();


or more compactly:


((A*)NULL)->~a();


Now, as long as nothing in the destructor actually tries to access the this pointer (by accessing data members for example), then all is well. The destructor is called and no object was ever created.

What is this useful for? I have no idea, but one thought that I had centered around one particularly special behavior of destructors. They automatically call the destructor of the parent class. Every other type of member function doesn't do this. Parent class versions of functions much be explicitly called. In some cases, this can be frustrating, especially in template classes where the parent class may be hard to determine.

In order to call a constructor without creating an object, we can use a special feature of C++ rarely seen outside of things like STL and embedded code, placement new. Placement new is just like new, except that it doesn't allocate memory for you. It leaves the memory allocation up to the programmer. Here's what it looks like normally.


void* ptr = malloc(sizeof(A));
A* a = new (ptr) A();


The syntax is a little funny, but that's okay. All we're doing there is calling the constructor member function using our own pointer (ptr) for the this pointer instead an automatically generated one.

So, using the same trick of using NULL instead of a valid pointer as we did with the destructors, we can do the same with constructors:


A* a = new ((void*) NULL) A();


Except it doesn't work. At least with gcc. The constructor never is called since the this pointer is NULL. Well, no worries, we're not trying to actually do anything with the this pointer, so we just need to pass in something that the compiler thinks is good.


A* a = new ((void*) 1) A();


Let's get rid of the assignment, since we're not going to use that pointer anyway.


new ((void*) 1) A();


And voila, we're calling constructors. No object needed.

One key point here that should be repeated is that none of this will work on destructors or constructors that actually try to dereference the this pointer in any way. The most obvious time this is done is when accessing data members. Another is calling virtual functions, since the virtual function table will need to be referenced. Also, any class hierarchy that includes virtual inheritance won't work since that mechanism uses the this pointer as part of knowing what destructor to call.

Labels: ,

Thursday, January 20, 2011

Emacs for Visual Studio users

Now that I'm using Linux to do all my development, I'm finding that a few things that I got used to in Visual Studio can be a little more difficult in emacs and a terminal. However, I'm finding that emacs generally has all the features I'm looking for and more if I take the time to learn them. Here are a few features I used in Visual Studio for which I've found equivalents in emacs.

Find in Files



"Find in Files" is a particularly useful feature in Visual Studio. For a while I was just using grep in a terminal and manually jumping to files it found. Slow and annoying. M-x find-grep is just what I was looking for. It would be nice if I could more easily tell it not to search everything and just *.cpp and *.h files for example.

M-x find-grep-dired puts the found files in a dired buffer (something I need to learn more about) and lets you do things like query-replace on a marked file. I haven't used this but it seems much more powerful than Visual Studio's system.

Debugging



Until I'm convinced otherwise, I still think that Visual Studio's debugger is the best in the business. Qt Creator comes close but the rest of the interface there isn't so hot. Emacs with gdb is surprisingly good and much better than the last time I tried using it a few years ago.

One problem is that I can't set or even enable a breakpoint while the program is running. Sometimes this is really useful as you have to run some code that will hit the breakpoint a lot before the one time you're interested in. Sometimes, it's really a matter of clicking "enable" at just the right time. Conditions help here, but sometimes it's just easier to enable when you need to.

Saving breakpoints was something I didn't think I could do, but the "save breakpoints" command seems to overcome that. Not as clean as Visual Studio, as I have to "source" the resulting file when I restart.

One command that has promise is rbreak, which I can use to set a breakpoint on all functions which match some regex. I couldn't get it to work however. It seems to find all the functions, but when it tries to set the breakpoints, it can't find them and asks if I want to delay setting them. Bug.

File Navigation



I like "C-x b", which allows you to load existing buffers quickly. I think there was something in Visual Studio that did this, but I never used it. If anything, I don't think it had tab completion, which emacs does.

Labels: ,

Tuesday, January 04, 2011

Switching on Boolean Conditions and Flags

I just posted an article over at CodeProject.com about what I call a boolean switch or switch flags (as the library I wrote is called). I've thought a lot about it over the years and implemented in a couple ways. It reduces the complexity of nested if statements. Basically, it allows for code like this:

switch_flags_2(a > b, c != d)
{
case flags_2(T,T):
// only execute when "a > b" and "c != d"
break;
case flags_2(F,X):
// execute when "a > b" is false
break;
}

Labels: , ,

Friday, December 03, 2010

Gnome Panel Applets

Just learned about Gnome panel applets because I wanted to make one to track my time at work. FYI, the Gnome Panel Extensions project is dead, or it never was really alive in the first place. I asked about this in IRC to which the response was:

for C, this http://projects.gnome.org/ORBit2/appletstutorial.html is ancient, but I think it's still more or less up to date. Not much has happened on the applet api front since forever. Python is the other reasonable choice and http://library.gnome.org/devel/panel-applet/stable/

panel-applets can use d-bus now http://live.gnome.org/GnomeGoals/AppletsDbusMigration not that much of a difference though
good point

and of course there's the fact that if gnome-shell actually does become successful in 3.0, applets go the way of the dodo along with the panel

We'll see if I get around to writing one. It's too bad that the panel extensions project is dead because they had some pretty good documentation. A simple tutorial or some sample code would be nice...

Labels: , ,

Wednesday, November 24, 2010

Exceptions are Faster

There's a lot of C++ hating around these days. This hate doesn't always come from the world of young bucks in love with Python. Seasoned C programmers like to hate on C++ for it's nice features. Because, as all good purtitans know, anything that feels good or makes life easier must be bad.

One particular C++ language feature that is generally avoided are exceptions. Even C++ programmers, who love exceptions for their ability to clean up ugly error handling code, are guilty of this. The general consensus seems to be that exceptions should only be used in parts of code that aren't time sensitive. Cache invalidation and all sorts of other badness are usually the reasons given that exceptions are slow.

The alternative in that situation is to use return codes. Yeah, sure they're ugly and use up that nice return value slot that could otherwise be used for something nice, but nothing is sacred when performance is required.

Well, I was thinking about that today and decided that this is all wrong.

The logic is this: In order to handle return codes properly, you must check them all the time. When you're writing time sensitive code, checking an error code that isn't going to be set 99.9% of the time is a big fast waste of time. In fact, looking at any flag that isn't set 99.9% of the time is really stupid. There's usually a better way to handle the logic. Spending the same amount of time for rare cases and common cases doesn't make sense. It's okay for the code that handles rare cases to be slow as long as the common case is as fast as possible. The overall speed won't be significantly affected by the rare case.

This is why exceptions are so great. With exceptions, you don't actually check anything most of the time. In other words, the common case of no error, takes no time at all. The compiler takes care of figuring out where exceptions should be caught at the points in the code where they're thrown. The way it does that is to simply "goto" the catch point. When using an error code, the calling code is checking for the error code every time. Yeah, it's slow because it's jumping all over the place. But so what? It only happens on rare occasions, which can be slow. If your code is designed such that errors are relatively rare occurances (as it should) then there is likely very little impact. Of course, if you're using exceptions for program logic, then well, you're doing it wrong.

All right, here's the proof that exceptions are faster than return codes. I created simple class that increments a value until it hits some maximum value. It is considered an error when it hits that maximum value. The return value version of this simply returns false when an error occurs, while the exception version throws an exception.

The return value version:

class inc
{
public:
inc(int m) : m_max(m), m_count(0) {}
bool go(int& x)
{
if (m_count > m_max)
return false;
x = ++m_count;
return true;
}
private:
int m_count, m_max;
};

int main()
{
int count = 1000000000;
inc f(count);
int x;
while (1)
{
if (!f.go(x))
{
printf("error\n");
return 1;
}
}
}

The exception version:

struct my_exception : std::exception
{
virtual const char* what() const throw () { return "error"; }
};

class inc
{
public:
inc(int m) : m_max(m), m_count(0) {}
int go()
{
if (m_count > m_max)
throw my_exception();
return ++m_count;
}
private:
int m_count, m_max;
};

int main(int argc,char** argv)
{
int count = 1000000000;
try
{
inc f(count);
int x;
while (1)
x = f.go();
}
catch (std::exception& e)
{
printf("%s\n", e.what());
return 1;
}
}

Before we cut to what you're waiting for, the benchmark, let's look at a couple things here.

First, the exception version is more self-documenting. When the error occurs, it's clear what the error is. It also catches more errors than just the one I'm aware of. Any other standard exceptions will be caught and the program will then exit gracefully with a possibly helpful error message. To accomplish this with the return code version, we would have to setup a error code system with associated enums, functions, etc. With this system, we just hook into the already created std::exception class.

Second, the code for the exception version is more elegant. Take the signture for the "go" function for example. In the return value version, I'm already using the return value for an error code, so I have to return the value by parameter reference, which isn't the natural way you'd want to do this. The exception version does the natural thing and just returns the value.

Now, the benchmark. I didn't do lots of testing with lots of compilers and so forth. Feel free to do so and torture me mercilessly, but I have my doubts that you'll get widely different results. On my machine here at work, an i7, the above code runs in about 4.8 seconds when using return values and 3.6 seconds when using exceptions, a 33% improvement.

Labels: ,

Friday, June 22, 2007

My Confession

I have a confession to make. Forgive me. Wait, don't forgive me. I'm completely unapologetic. I am a programmer, and I don't write comments. I just needed to get that off my chest.

I don't believe in comments.

I have been writing a lot of fairly complex code lately. And all the while, the voices of dead Computer Science professors have been speaking to me. They repeat the mantra of good code commenting. I feel guilt, like when I go to church. Or when I don't make my bed in the morning. Of course, not one of them is able to give me any good suggestion of what a good set of comments is. They just tell me what isn't a good comment. So does that mean that anything else is a good comment? Like lots of swear words in the code. That's probably more useful than real comments, because they make me laugh and keep me from falling asleep at the keyboard.

Good comments, I'm told, are not just a rehash of what is already in the code. Well, if it isn't already in the code, then it isn't much use to the program is it? I don't believe in comments. I think they are mostly a waste of time. Maybe not for you, but for me they just make my life difficult. I have to make a context switch to English in order to write them. That takes time and just serves to confuse me.

Whenever I write English, I take the audience of my writing into account. Who is the audience for my comments? Some moron with a basic C++ book on his desk? Or the great man himself, Bjarne Stroustrup? Bjarne is pretty smart and will probably be able to figure out my code just fine without me, or my comments. Because he speaks C++. I speak C++ too, so that's how I like to communicate with computers and other people who speak the same language.

So I don't write comments. I'm one of those people who likes to use good variable names, good function names, and good file names. When I look at others' comments, I don't usually trust them, because they often don't make any sense. Or they are just plain wrong. That's just awesome. Like the time I first starting programming and I spent two days wondering why the second member of a pair of ints (pair) was always zero, even though the comments said it should contain some valuable piece of information. Actually, it was the first member, not the second one, which I finally figured out by actually looking at the damn code. Wonder of wonders, the code actually told me what the code did. Amazing.

I think that instead of comments we should put quotes of great authors at the top of all our code. That way, when people read our code, they will think that our code is profound, because we quote the greats of our time like, Dostoevsky, Helen Keller, or Dave Barry. And the best thing would be to just randomly pick those quotes so that when people try to make some connection between the code and the quote, they'll spend lots of time trying to figure out. Then they'll feel stupid, but won't want to admit it and we can fun of them when they can't explain the connection. And we won't have had to be smart at all, because all those people that we referred to are smart.

Have I even written comments? Of course, I slap all my comments in the headers, when I don't feel like writing documentation. Or when the function name is getting too long. Or when some fellow programmer makes me feel guilty for not following the religion of comments. What is the point of writing commments if the function name tells the whole story? Take vector for example, the size() function returns, guess what, the size of the vector. I know what you're thinking, that is completely non-intuitive. It's got to be commented. Look, if the function name can't tell you what the function does, then maybe you should change the function name. And if your function name gets too long, then maybe your function is doing too much.

Good, maintainable programs are easy to understand not because they have lots of comments explaining their complex structure, but because they are straightforward, not complex. Complex is a synonym for spaghetti. Code should be more like ravioli. Good ravioli, not that crap they give you in restaurants. Chef Boyardee is delicious. The mental model of a good program is easily understood by normal humans. And if that mental model is nice and straightforward, then the functions that act on it should also be straightforward. A function called get_ the_ thing_ and_ reroute_ the_ other_ thing_ with_ the_ thing_ you_ have_ from_ before() doesn't need to commented, it needs to be thrown out. The class it lives in probably does too. It's doing too much.

I'm religious, but not about programming. In religion, there are things that you believe just because they seem right. Code comments may feel right, but they just don't prove their value outside of giving people a good feeling. I'm going to love my enemy for no good reason, because that sounds like a good idea. But I'm not going to type any more comments until I have a mathematical proof that it's good for me, like ravioli.

Labels:

Wednesday, September 07, 2005

CSS is Crap

Ok, so I think it's fairly obvious that I am big fat C++ bigot. That's probably because I've programmed in C++ more than any other language. So I'm a little biased. That's okay because C++ actually is better in many cases.

But because I'm the resident "computer guy" for various groups, like my family and friends, I regularly step out of the C++ realm and try other things. Take for example, web pages. I've done my share of JavaScript and PHP generated pages. But most of that was years ago before what I have been told is now the golden age of web development. Life was hard then, but back then we only had IE and Netscape. But a new day has dawned. A great leap has been made on the Interweb. With technologies like XML, CSS, XHTML, PHP, and the vast Java pile of beans, cheese, and who knows what, developing web pages is supposed to just be a piece of cake.

Recently, I tried to actually create one of these fantastic web pages using one or more of these technologies. After about a week of just trying to format a page without using those evil nested tables and using the magic of CSS, I started to cry for my mommy, the only person who might care about my personal hell.

Why in heaven's name does this have to be so damn complicated? I've learned numerous languages and file formats over the years, so I think I have an idea of how to go about reading a language spec and understanding what it does, and then how to use it effectively. Has anyone actually tried to use the CSS spec or any of the docs out there to get anything done? No wonder there isn't a browser out there that actually implements it properly. It is so generic as to be completely useless.

I really feel for the children of those wrote that stinking pile of MIT-grad generated uselessness. I'll bet they tell their kids when they ask for math help, "Okay, I'm not going to actually tell you how to do that math problem, I'm just going to give you these advanced level calculus books and let you figure it out yourself. It's all very clear once you understand the analysis of infinite-dimensional ring theory."

Yes, I understand that there should be many ways to skin a cat, but CSS gives you about seven hundred. And that is just the number of ways to tell it how big to make your fonts. Not that any of them actually allow you to do that. They all just give the browser a suggestion. And since we really do need 17 browsers out there (for competition right?), there are 17 different ways to interpret what I put in my CSS. In other words, my page looks like crap on anything but Opera version 6.6.6.

I missed the dot com boom. I was working. Is this the nonsense that they spewed out with all those billions? Look folks, this is what you get when let philosophy and foreign film majors get into engineering. Heaven forbid that someone disagree with someone else and the person with the better solution actually win the argument. That would be solutionism. Almost as bad as racism, ideaism, or using your brain. They put everyone's solution in there. Just in case people want to use CSS to teach their dog to hate kids with green eyes.

All those spare web developers are "rethinking their careers" because they sucked at them. No wonder they didn't get a lot of fulfillment from their jobs as web lackeys. If I sucked at something, I don't think I would like doing it either.

Some people just need to say, "That sucks. Really it does, and here is why." They want to think that everything has a meaning and value. News flash, some things just suck. They're crap. They should be thrown out. Figure out the right way to do the job, and leave everything else behind. Like 90% of CSS.

And your little dog too.

Labels:

Sunday, June 26, 2005

Java is the worst of both worlds

Unless you were sleeping on the first day of your programming languages class, then you know that there are two kinds of programming languages, compiled and interpreted. Compiled languages are those that are routinely converted to some other language (usually assembly/machine code) for execution. Interpreted languages aren’t. Another program interprets the code on the fly and makes the program work. And no, pseudo code is not a programming language, it’s a human language. Don’t even dare confuse the two. See the entry titled “Humans are not Computers” if you disagree with me. You will realize the error of your ways.

Both types of languages have their advantages. Compiled languages tend to be able to squeeze the most out of their host platform because there is no interpreter to slow things down. However, much of the “information” about what the program is supposed to do is lost since we’re converting from one language to another. You always lose some insight when you convert from one language to another.

Interpreted languages on the other hand tend to be more flexible and easy to use. Because interpreted languages don’t have to worry about what the code actually does until it has to do it, it can allow a lot of ambiguity. The interpreter can figure out a lot more things by itself if it has the data that needs to be processed at hand when it interprets the code. A lot of flexibility comes from the ability of the interpreter to interpret any code given it, even if that code didn’t exist until runtime. The PERL eval() function takes PERL code as a string and can interpret it on the fly. Also, interpreted languages are executed on the fly, the interpreter has more information about what the programmer meant to do, so it can optimize many things that a compiled language can’t. This capability hasn’t been exploited as much as it might be. The Java folks have done some work with just-in-time compilation. I suspect this is where they get ability to hit benchmarks as well or better than C++ code.

Ah, Java; the savior of all of use who are trying to write software for everything from mainframes to calculators to cheese slicers and unmanned exercise machines. Java is the worst of both of these types of languages. It isn’t an interpreted language, it’s compiled. But it isn’t compiled to machine code to take advantage of native code, it’s compiled to Java byte code, which is then interpreted. “But byte code interpreters are really fast!” they say. I don’t care how fast they are, unless they’re so fast they don’t actually run, I don’t much care. If they take time, they take time. You just can’t get around that.

Now I have nothing against interpreted languages. PERL is one of my favorite tools. But look, Java just doesn’t give you any of the flexibility of an interpreted language. Once you’ve compiled to byte code, you’ve gotten rid of all that semantic goodness that is found in the original program. So you’re interpreting without any of the benefits of interpreting, and compiling without any of the benefits of compiling.

I hear folks saying, “what about the platform independence? Isn’t that a great thing?” Yes, yes it is. But there a lot better ways to solve that problem. On the compiled end of things, you can use platform specific code wrapped by platform independent APIs like STL, Boost, Qt and wxWindows. Or just write platform independent code with conditional compilation (#ifdef’s for the buzzword impaired).

On the interpreted end, things are even easier. Just write platform specific interpreters. This is probably the way to go when performance isn’t an issue. And even if it is, then JIT techniques might help your cause.

Java just isn’t the answer.

Labels: ,

Tuesday, May 17, 2005

Writing C in C++

I’m sure that you’ve heard of the term C/C++ as if somehow they are so interrelated that they can combined into a single term. C and C++ are about as close as a lilac bush and George Bush. Sure they share some of the same terminology but you wouldn’t want to meet one of them in a dark alley at night.

C is good for one thing, being one step above assembly code. Anyone who tells you otherwise is lying to themselves. Everything about C is about making things you do in assembly easier. The perfect example is the switch statement. There is no rational reason to force the programmer to put break statements at the end of every case. It doesn’t make any sense unless you know that the switch statement is likely to be implemented using jump opcodes. Also, who in their right mind uses up an entire operator to implement bit shifting?! Unless you’re some sort of divide-with-shifts freak, then you’re just not going to use them very often.

And why do they call them function pointers? There’s no reason that the user should have any idea how functions are implemented, let alone knowing that they can be pointed to. The syntax for function pointers is bad enough.

C is a great language for compiler writers. For every construct in C, there is a fairly straightforward translation to assembly. This is of course the main issue behind all the complaints about C. It wasn’t designed to be a language, it was designed to easily translated. So it shouldn’t come as much of a surprise to learn that the guys who came up with templates never wrote a compiler. Sure, they took a class on compilers, but that doesn’t mean that learned to love their local compiler guy. Really, who complains the loudest about how hard it is to implement templates in C++? Compiler writers. More specifically, Microsoft’s compiler writers who proved that templates are hard by producing Visual C++ 6.0 where using templates is like trying to teach your dog new tricks only to find out that it is an armadillo. Sure an armadillo looks like a dog, but partial function template specialization looks likes it might work. But it just doesn’t. Whether you like it or not.

C++ is a boon to the programming world. It took C places way beyond where the compiler writers wanted to go, which is a good thing. When people start complaining about something, it’s usually a good sign that something is getting done. C++ doesn’t make any effort to be nice to compiler writers. This made getting Visual C++ done take way longer than Microsoft Bob, but it sure makes for a flexible language. Compiler writers don’t like that word, flexible. It means that they have to work. They have to work to take all the flexibility into account. But I don’t care, I’m not a compiler writer.

Someone invented C so they wouldn’t have to code in assembly, and someone invented C++ so they wouldn’t have to code in C. So if you’re a C programmer writing C in C++, then you’re basically installing an automatic garage door opener and then opening the door by driving into it. You’re not using the features of the language that you claim to embrace. Here are some of the features that C in C++ programmers tend to continue to use even thought C++ has surmounted their craziness.

First, function pointers. Virtual functions were invented so you freaks using function pointers could stop the madness. If you’re using a function pointer as a callback, then use virtual functions. They’re easier to use, more flexible and the syntax doesn’t look like monkey spew. There are numerous other reasons to use virtual functions beyond callbacks, so for those of you who think that function pointers are God’s gift, they’re more like Satan’s spawn.

Second, typedef’ed structs. Newsflash, typedef’ed structs are no longer necessary. You wouldn’t be using them in C++ if you knew why you had to use them in the first place. A struct is now an actual type. That was the whole point of C++. Making classes and structs act like native types. Along with this is the flawed belief in the difference between structs and classes. Repeat this mantra every morning in the shower if you still think that stucts and classes have some fundamental difference, “A class is just a struct where the default is private versus public.” There isn’t any other difference. No way, no how. Most compilers don’t even remember which is which.

Third, void pointers. They were a bad idea in C, but perhaps a necessary evil. But in C++, they’re just not at all necessary. Void pointers are not the tool of the super-hacker, they are the last resort of the design-impaired. Just because you don’t know of any other way to do what you’re trying to do with void pointers, doesn’t mean that using them is OK. It’s not OK. C++ provides so many ways to not use void pointers, that using them is a sign of your C++ ignorance. Go back ten spaces and read your beginning C++ book again.

Finally, using pointers to pass things by reference. I don’t care that you’re used to doing it this way. We just don’t pass things by pointer anymore. We pass them by reference. References are an improvement over pointers. Get over that they can’t be NULL. This is a good thing. 90% of crashes in C programs are NULL pointer dereferences. So it makes sense (yes, it actually does) that you should want to minimize the use of pointers. They don’t make you cool or more of a super-hacker because you use pointers for everything. They just make you reckless. References are safer than pointers. You don’t drive around your car without a hood just so you can have easy access to the innards when you need them. You open it as needed. Adding pointers is just like putting hood pins on a Pinto. Same goes for pointers. Use them as needed.

So what is the message here? If you’re using extern “C” at the beginning of your C++ code and telling your boss that you’re writing in C++, for all the rest of us who didn’t sleep through the nineties and have to read your over-syntaxed code, please go read a beginning C++ book and join the 21st century.

Labels: , ,

This page is powered by Blogger. Isn't yours?