Tooling around

September 24th 2009 09:26 pm

Some minor things:

Temporary confusion: On a mailing list the other day someone was having issues with the following type of code:

const char *name = m_obj.byteArray().constData();
printf("%s", name); // kaBOOM

So what was wrong? In this case, usage of a pointer that was freed. Freed, in this case, by the QByteArray object that was created and destroyed all on the same line. In other words, this part: m_obj.byteArray() returns a new QByteArray (called a temporary object since it is not named by the programmer). The .constData() tacked onto it grabs the address of the data in that QByteArray.

Unfortunately, by the time you’ve used the pointer on the next line, the temporary QByteArray has been destroyed. Now that pointer you have is dangling into unallocated memory and who knows what will happen. Maybe it will work, maybe it won’t, but it’s technically undefined behavior.

The solution is to assign that QByteArray to some local variable first, that way the compiler won’t destroy it on you. Also note that passing this pointer to an enclosing function is also fine, like this:

printf("%s", m_obj.byteArray().constData());

The compiler will make sure that all of the temporaries invoked to handle a function call will be alive until after that function has run (destroying temporaries is done as the last step of that entire expression). This is what makes the qPrintable() function useful.

Also I saw a interesting link about GCC optimization on Hacker News. Basically the -Os (optimize for size) flag ends up being the fastest compilation option in many cases. This is due to the fact that it takes so long to access data that is not in the cache for modern day architectures (in comparison to CPU speed) that it is often better to do a lot of extra work for the CPU if it will mean that the code size is smaller. I’ve used this flag for awhile with no ill effects (on the other hand, no blindingly obvious speedups either ;) It’s something to think about when you’re playing with your compilation flags.

Posted by mpyne under C++ & Tutorial & Useful Tricks | 4 Comments »

4 Responses to “Tooling around”

  1. Benoit Jacob Identicon Icon Benoit Jacob responded on 25 Sep 2009 at 07:08 #

    To me, this is a flaw in Qt’s API: since byteArray() constructs and returns a separate object, it should rather be named toByteArray(), as this is done in many other places in Qt, or perhaps asByteArray().

    The name byteArray() suggests that you access the underlying byte array.

    I would suggest the trolls to introduce toByteArray() and deprecate byteArray() in favor of it, if it isn’t too annoying for people whose existing code will suddenly produce warnings.

  2. Parker Coates Identicon Icon Parker Coates responded on 25 Sep 2009 at 11:49 #

    Benoit: That’s an excellent suggestion. byteArray() feels like a simple member getter. toByteArray() would make it obvious that something a bit more complicated is going on. And that would probably be enough to prompt the developer to read the docs and figure out how it actually works.

  3. mpyne Identicon Icon mpyne responded on 25 Sep 2009 at 14:10 #

    Benoit: Well in this case it would be whatever class defined .byteArray(). I never said that m_obj belonged to a Qt module. (In fact the instance I saw this type of thing happen used no Qt code at all). I changed the terms to be Qt-style to reflect Planet KDE readership but it’s all to illustrate an example.

    tl;dr: If you get a pointer from the object, and you’re not responsible for deallocating it, someone else is. That someone else must be alive for the pointer to be valid.

  4. Allen Winter Identicon Icon Allen Winter responded on 25 Sep 2009 at 15:32 #

    FYI, krazy2 checks for:
    [\w\s]+=\s*\w+\.(toLatin1|toAscii|toUtf8|toLocal8Bit)\(\)\.(data|constData)\(\)

    in perl

Trackback URI | Comments RSS

Leave a Reply