Wednesday, September 22, 2010

Let's Allocate Stuff!

Nobody's perfect, of course, but when there are so many things wrong with a small piece of C++ code, it's hard to be placid. How about:

  std::vector v = new std::vector;
  // ...
    v->push_back(new std::string("..."));
  // ...
  std::ostream *str = get_me_a_stream(...);
  for (int i = 0; i < v->size(); i++) {
    *str << (*v)[i]->c_str();
  }
  delete str;
  // loop to delete v and its elements.

Ow, my head is spinning from all of these needless allocations. Let's not wear out new and delete.

Well, if you first learn C and then learn C++, your head might still be in Pointer Land. But the unnecessary call to c_str() makes it hard for me to get any work done.

Saturday, August 14, 2010

gcc: error: expected `)' before '&' token

Duplicate post here just to get two related error messages into page titles. That's as much SEO as I know how to do.

If you get this error from g++, and everything looks correct to you, maybe you are defining a constructor without qualifying it with the class name. See the example on this post.

gcc: error: expected unqualified-id before ')' token

I was scratching my head for a few minutes over the g++ error message in the title. Google turned up a couple of red herrings, like this one at Stack Overflow where a clueless noob #defined the name of his class.

My mistake had been to define a constructor without putting the Class:: in front of it:

    Class() // WRONG!!!
    : Super(), _duper()
    {
    }

instead of

    Class::Class()
    : Super(), _duper()
    {
    }

It wasn't as stupid as it sounds, I was cutting and pasting inlined functions into the .cpp file.

Wednesday, July 14, 2010

Can't Locate Object Method via Package

I recently got a confusing Perl error message for a line of code that I thought was a simple assignment to a hash member:

Can't locate object method "patterns" via package "objdir(/[^ ]*)?" (perhaps you forgot to load "objdir(/[^ ]*)?"?) at ./filter.pl line 24.

A Google search turned up many forum entries asking about the message, but they all had to do with open-source projects where there was indeed a package method call that had gone wrong.

After I rubbed my eyes long enough, it was obvious what I had done: left the '$' off the front of the hash reference. I had typed:

    patterns{"objdir(/[^ ]*)?"} = "dirs/objs"; # WRONG!

instead of:

    $patterns{"objdir(/[^ ]*)?"} = "dirs/objs";

I even had use strict; use warnings; on, but only got the error message. Anyway, since Google didn't help me out, let's see if this page with the error text in the title floats to the top and helps someone else out someday.

Friday, June 18, 2010

Blessed Mother of Commented-out Code

It's the little things in life that give pleasure, isn't it? Like the lovely comment below, which has adorned a source file at my company for nearly sixteen (16) years now (meaning the file is at least 5 years older than the company).

/*****************************#if (0) //[
// Marked code has been deleted   -- XXXX (18 August, 1994)
// No need to check whether the value is X/X/X
// Only the size is to be checked which has been done
[[[ DELETED

      char  val;

      val=tolower(*((char*) var)->getValue());
      if ((val != 'X') && (val != 'X') && (val != 'X'))
          return 0;
]]]
   #endif //]
*************************************/

There are many facets to this beautiful gem. First you'll notice that there is a nice C++-style // comment -- complete with the date and the signature of Mr. XXXX -- itself commented out by a C-style /* comment. Too bad the dead code isn't commented with //, so that my grep for tolower would have stood out as unnecessary.

But look, really the /* is there to comment out an #if 0. The guy must have wanted emacs to colorize the dead code as a comment -- I don't think emacs had font-lock back then, but there was the hilit19 package.

Still, you can't be too careful, so let's also wrap that code up in a [[[DELETED ... ]]], in case there is some human that can't read the C comments and the if-0, but who will understand what "triple-bracket DELETED" means.

Finally, it appears the conditional was originally written as #if (0) [ ... ] -- was that ever legal C? -- but when that wouldn't compile, the brackets had to be commented out, because every character in this file is too precious to ever delete. This must be the bad code afterlife. You can check out anytime you like, but you can never leave.

How did all this happen? Is it an accumulation of different commenting-out strategies that occurred over time? Or is it just an unfortunate snapshot of one man's frenzied efforts to remove 3 lines of code without actually deleting anything? Sadly, we can only speculate on what happened, because these lines entered our repository in exactly this condition over 10 years ago.

I love deleting dead code, but I can't touch this one. It's an antique. And so ugly that it's beautiful.

Thursday, June 10, 2010

Csh Skips Last Line in Script

Oh, joy.  I've found another thing to hate about csh.  If the last line of your script doesn't have a newline after it, that line won't be executed.  It will be silently ignored.  That isn't very useful.

If emacs knows you are editing a shell script, it will automatically put a newline at the end if you didn't do it yourself.  But if you have an ordinary text file that you will run with source, it better have a newline at the end.  You can get emacs to either ensure that or warn you about it by adding one of the following lines to your .emacs file:

;; Quietly add a newline if missing.
  (setq require-final-newline t)

  ;; Ask if you want a newline at end of file.
  (setq require-final-newline 'ask)

Googling for this problem, I found another nice csh rant.

Wednesday, April 28, 2010

Tcl Case Analysis Lunacy

This goes way back to the roots of this blog. Complaining about Tcl, and complaining about code that breaks down into unnecessary and confusing case analysis -- those topics were the first three posts here.

Unsurprisingly, the toy language that is Tcl is serving me up some ridiculous case analysis. It has to do with the C++-side of a Tcl integration. When you look at the internals of the language objects created by the Tcl interpreter, some things that are conceptually the same have different internal representations. It's bad enough that I have to succumb to case analysis to figure out what's what: but on the other side of that wall, Tcl had to do some case analysis to put them all in different representations! Bad, naughty Tcl.

Here's what's bugging me. When you look at a Tcl_Obj over in the C world, it has a typePtr member to distinguish different types of things:

  • A simple name like A has a NULL typePtr.
  • So does a list of things in braces, like { A B }.
  • A name with some special characters like A[0] has type "string".
  • So does a list of things in braces which extends over a few lines, like:
    { A \
          B }
    
  • An explicit list like [list A] has type "list".
  • A quoted string like "A B" has NULL. At least I think so. I lost track.
So obviously there are a bunch of if statements in the back-end tangling stuff up like this. But it's nearly impossible to untangle it on the C side.

Stupid Tcl. Stupid case analysis.