The difference between Qt::Key_Enter and Qt::Key_Return

— richardwb on Wednesday, June 10, 2009 @ 10:48

It's specified in the documentation, though in a slightly subtle manner. Essentially, Qt::Key_Enter is the keypad Enter, while Qt::Key_Return is the "regular" Enter, the one which you normally use while typing.

Comments

Visual Studio 2010 sounds pretty neat so far

— richardwb on Tuesday, June 09, 2009 @ 10:04

I'm a very big fan of the Visual Studio IDE (I think it's the best around, for any platform). However, Microsoft has historically put less of a emphasis on the C++ portion and the past couple of versions have had only minor bullet points on the C++ side.

I think they've wizened up a bit and the next Visual C++, 2010, has some notable improvements in store (C++0x support, for one). They've also put a lot of work into completely reworking their C++ IntelliSense engine. There's not much for me to say, really, as they have a great blog. I'll just highlight some of the articles I found the most interesting, which coincidentally all focus on IntelliSense:

Comments

Qt: staticMetaObject is not a member of...

— richardwb on Friday, May 29, 2009 @ 21:11

Just got this error message while compiling a tiny class that derives from QTreeWidgetItem:

error C2039: 'staticMetaObject' : is not a member of 'QTreeWidgetItem'

What this is saying is that QTreeWidgetItem does not inherit from QObject, meaning that your own, singly-inherited class also does not inherit from QObject. Inheriting from QObject is one of the prerequisites to using the Q_OBJECT macro, which, if you're anything like me, you automatically insert into any Qt GUI related class.

If you're not using any of the meta object stuff in your subclass, such as signals/slots or properties, just take out the Q_OBJECT macro. If you need to use signals and slots, you'll need to make your subclass multiply-inherit from QObject as well. If you take this route, remember that "Multiple Inheritance Requires QObject to Be First", otherwise you'll get either the same error as above, or something along the lines of "YourClass inherits from two QObject subclasses" from the moc.

Comments

Captchas shouldn't be the default defense against bots

— richardwb on Thursday, May 21, 2009 @ 15:17

Captchas are useful to prevent bots or similarly automated activities from occurring. However, they're not perfect and many of them can be broken with a targeted attack. In a sort of arms race fashion, captchas get more and more intricate, but some take this a bit too far and aren't really even human solvable.

In any case, large sites have to have some way to separate bots from humans, and captchas may be the only solution. It's still an arms race, but at least the large sites have the resources to throw at it.

What about the small sites? Your blog about your cat? Your forum for fellow gum-chewers? Do you really need (or want) a captcha for these types of sites? Unfortunately, what happens is a crawler stumbles upon your site, notices it uses some popular blog or forum application it knows about, and attempts to register so it can subsequently flood your site with spam. If you use a popular application, such as phpBB3 (for the sake of argument), once the generic, built-in captcha gets broken, all non-customized phpBB3 sites are vulnerable. So a spammer just needs to try to break this one particular captcha and suddenly they've unlocked the ability to spam millions of forums. It provides the volume that spammers need to make spam work.

What I suggest instead is that the default mode of operation for a forum (or any application, really) should be to ask a simple question upon registration, with both the answer and question provided by the person who is running the site:

Q: What is my cat's name?
A: Fluffy

Q: Which of the following is a brand of gum? Oreos, Jellybeans, Trident, Snickers
A: Trident

Incidentally, yes/no type questions should be disallowed, as the answers ('yes' and 'no') would be common enough to automate.

Now, spamming your forum requires actual human intervention. Obviously this sort of approach will fail if you have a large or popular site, but if you own such a site you already know you have to take more steps to protect your site.

One potential problem is I could see lists of questions/answers being hand-generated and passed around, but this could be mitigated by expiring questions/answers after some time. If you're feeling particularly clever you could even flag the old answer as being a 'bot-answer', which might work well in concert with an Akismet type service:

Q: How old is my cat?
A: Fluffy (hello, bot!)

Anyway, I feel that captchas are a bit of dead end in terms of anti-spam measures for small sites. Small sites are not typical targets for spammers, as the reward is not worth the effort. However, if all these small sites are protected by the same captcha, breaking that captcha gives that spammer access to (small-sites × millions), which is worth the effort.

Comments

More thoughts on Qt 4.5

— richardwb on Thursday, May 07, 2009 @ 16:35

I've been using Qt 4.5 for a couple more weeks now and I've had a few more thoughts on the framework.

  • I don't know if I could handle using the plain Win32 API for GUI ever again
  • Even with Qt's "parent handles the deletion of its children" memory management system it's still easier to use (and reason about) shared_ptr or another smart pointer, as long as you're not working with widgets or similar GUI elements. If you're working with GUI elements, Qt's memory management works perfectly and makes sense.
  • You can assume that any addWidget()-like function will take ownership unless explicitly stated otherwise. I still wish they would just say straight out that "this function takes ownership".
  • In my opinion the documentation would be much improved for newcomers if they had a "Qt Best Practices" section. You can get a sense of how things should be structured if you look at their sample programs, but there's a lot to go through.
  • Other than those two nitpicks, the documentation is consistently quite good.
  • I would suggest that you avoid using the Qt containers and instead favor the standard C++ containers whenever possible. There's less to learn, and most C++ programmers will have a firm grasp of the containers in the std namespace. Some Qt functions do return QStringList or some other Qt container, in which case you may as well just leave it in the container you get it in.
  • On the other hand, if you're going to use Qt, you may as well use QString everywhere. It's used extensively through the Qt framework, so you won't be able to avoid it. It's a pretty decent string library anyway, with plenty of useful functions, and it handles Unicode cleanly in my experience.
  • QTextEdit isn't particularly performant, particularly when you resize it and it has to perform lots of word wrap calculations. Use QPlainTextEdit if you can.

Comments

A really quick boost::random guide

— richardwb on Wednesday, May 06, 2009 @ 20:03

This is a really short and quick guide on how to use boost::random. The best place to start is, as always, the documentation, but Boost also provides a simple sample program that covers the library in a good "how to get started" fashion.

What I'm about to write here is even shorter and less detailed -- it's just the basic code needed to generate some random numbers.

// Initialize a random number generator.
// Boost provides a bunch of these, note that some of them are not meant
// for direct user usage and you should instead use a specialization (for 
// example, don't use linear_congruential and use minstd_rand or 
// minstd_rand0 instead)

// This constructor seeds the generator with the current time.
// As mentioned in Boost's sample program, time(0) is not a great seed,
// but you can probably get away with it for most situations.
// Consider using more precise timers such as gettimeofday on *nix or
// GetTickCount/timeGetTime/QueryPerformanceCounter on Windows.
boost::mt19937 randGen(std::time(0));

// Now we set up a distribution. Boost provides a bunch of these as well.
// This is the preferred way to generate numbers in a certain range.
// In this example we initialize a uniform distribution between 0 and the max
// value that an unsigned char can hold (255 for most architectures)
boost::uniform_int<> uInt8Dist(0, std::numeric_limits<unsigned char>::max());

// Finally, declare a variate_generator which maps the random number
// generator and the distribution together. This variate_generator
// is usable like a function call.
boost::variate_generator< boost::mt19937&, boost::uniform_int<> > 
    GetRand(randGen, uInt8Dist);

// Generate a random number
int aRandomNumber = GetRand();

Comments

Namespaces are one honking great idea

— richardwb on Wednesday, April 29, 2009 @ 09:17

The title of this post comes from the last line of The Zen of Python.

It applies to C++ too: namespaces are great. Namespaces let the Boost folks contain all sorts of widely varying libraries without having to worry about naming collisions in user code. Namespaces let you mix multiple libraries easily and safely. Namespaces let you group sets of related free functions together, without needing a class. Namespaces also let you work around one thing I've always found a bit unusual with enums: the way they don't have their own scope.

enum ValidValues
{
    Value1,
    Value2
};

This ends up declaring Value1 and Value2 in the underlying scope. What I like to do is wrap the enum in a namespace:

namespace ValidValues
{
    enum Enum
    {
        Value1,
        Value2
    };
}

This sticks Value1 and Value2 in the ValidValues namespace. The only disadvantage is declaring a variable of this enum type gets a bit silly and inconsistent. For example:

ValidValues var = Value1; // error, ValidValues is a namespace, Value1 is undefined
ValidValues::Enum var = Value1; // error, Value1 is undefined
ValidValues::Enum var = ValidValues::Value1; // okay

This is yet another area where C++0x will offer its own solution, in this case, strongly typed enumerations.

Comments

Right aligning a button in a QToolBar

— richardwb on Thursday, April 23, 2009 @ 08:32

Sometimes you will want to add a right-aligned button to a QToolBar. The first thing that probably comes to mind is to add a QSpacerItem to the toolbar, but that won't work as QSpacerItem is not a child of QWidget, so you can't use the addWidget() member of QToolBar. Instead, make a basic QWidget, set its sizePolicy to Expanding, and add that widget to your QToolBar. For example:

QWidget* spacer = new QWidget();
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// toolBar is a pointer to an existing toolbar
toolBar->addWidget(spacer);
toolBar->addAction("Right-aligned button");

If you end up using a lot of these spacers you could even create a subclass.

Comments

Qt 4.5

— richardwb on Monday, April 20, 2009 @ 09:16

Qt is a well known cross platform framework. It's probably most well known as the framework on which KDE is written.

Anyway, over the weekend I experimented with it a bit, and in terms of C++ GUI development it's a breath of fresh air. It approaches the ease of use of the .net GUI facilities, which is great for a language with no built in introspection abilities. The "moc" preprocessor that Qt requires (that lets them do things such as signals and slots) you to run on your source files is still a bit weird, but it's really not as bad as it seems.

The Qt framework is also impressively comprehensive, making it very easy to code applications directly against Qt, instead of coding against a particular OS or a particular compiler.

The style of the framework itself is more traditional than the common notion of modern C++, having more of an emphasis on subclassing and overriding virtual functions than on generic algorithms. The memory management system is definitely foreign: they encourage you to allocate on the heap, yet there are very few delete statements. The way it works is that QObjects (Qt's base class) accept a pointer to a parent in their constructor, which makes that particular QObject a child of the parent. When the parent is deleted, it takes care of deleting all its children. It's a change from RAII, for sure.

It also takes a couple of hours to compile Visual Studio compatible versions of the various components, so don't do it as a last minute thing.

Comments

Porting a Winsock application to Linux...select(2) is not as simple as MSDN makes it seem

— richardwb on Friday, April 10, 2009 @ 17:54

I'm in the middle of porting bits of a Winsock application to Linux. Luckily when I first wrote the networking bits I had made an effort to write it in a somewhat cross platform manner. As a result, I stuck to select(), send(), recv(), and all the other function calls that Winsock provides that are close to the Berkeley socket interface. Things go pretty smoothly, although for some reason there's this really weird pause when connecting that didn't exist before...

Finally I hit a point where, for some reason, I couldn't establish a connection to the server and it just times out. That's really strange, so I threw good old debug statements all over the place and find out that this select() call is not doing much of a select:

if (select(0, &rdset, &wtset, &errset, &tv) > 0)

Notice the 0? MSDN states that it is:

nfds
Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.

Then I check the equivalent docs on the Linux side of things:

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

Well, if I set nfds to 0, select() won't be doing very much selecting! Windows has FD_SETSIZE at 64 by default, and it ignores nfds and just checks whatever descriptors are in the fd_sets that you pass to it. Linux considers sockets and files the same thing, and thus has a much higher FD_SETSIZE (1024 and 4096 seem to be common). You don't want select() checking 4096 descriptors, so you set nfds to the highest file descriptor you want it to check, plus one. (As an aside, setting nfds to FD_SETSIZE is a bad idea.)

if (select(my_socket + 1, &rdset, &wtset, &errset, &tv) > 0)

Where my_socket is an appropriate file descriptor (such as the one returned by socket()). This works just fine in Windows too, since it ignores the nfds parameter.

Armed with this newfound knowledge, I go and fix all the other select() statements in my code, which ends up fixing the weird pause as well. Effectively, without a proper nfds value, select() just acts as a timer and blocks until the specified amount of time has elapsed.

Comments

All AJAX sites need a fancy indeterminate progress indicator...

— richardwb on Sunday, April 05, 2009 @ 20:22

Ajaxload is a neat little site that generates those throbbers/spinning wheels that are in vogue nowadays. Your website/application won't be complete without one, after all.

Comments

PNG has a well designed magic number (or FourCC)

— richardwb on Friday, April 03, 2009 @ 17:20

Even with all the XML floating around, binary formats still have their place. It's good practice to place an identifier at the beginning of the binary file, so that the file type can be determined even in the absence of a proper file extension.

The simplest route to take is to just stuff some plain text there:

[M Y F I L E][rest of file]

However, consider following the design of the PNG magic number, described in detail in the PNG book. With some really neat design they are able to quickly detect some common forms of corruption caused by an incompatible transfer mechanism. In that case your identifier may look like:

[\211 M Y F I L E \r \n \032 \n][rest of file]

With an identifier like this many common forms of transfer corruption can be quickly identified, and you can spit out a simple "corrupt file" message instead of trying to read a broken file.

Comments

Don't forget about copy constructors and the copy assignment operator

— richardwb on Friday, April 03, 2009 @ 12:30

Something that I've always found handy to do is to decide, right away, what the copy semantics of a particular class are. Generally it turns out that it makes no sense (or is a lot of work) to allow copying, in which case the standard approach is to define the copy constructor and assignment operator as private.

An alternative approach and one that I think is a bit more self-documenting, is to inherit from boost::noncopyable. This achieves the same effect and makes it immediately obvious that the class will not allow copying.

class MyClass : boost::noncopyable { };

The most correct way to use boost::noncopyable is to inherit it privately, since inheriting it publicly could let people do really funny stuff like:

void stuff(const boost::noncopyable& obj);

(more details here)

Comments

A RapidXML gotcha

— richardwb on Thursday, March 26, 2009 @ 13:00

I just spent a couple of hours trying to track down why I was seemingly losing data values while modifying nodes in the DOM. It's spelled out in the documentation, but it definitely threw me for a loop (I would consider this behavior surprising). Basically, RapidXML gives you the ability to assign/modify the value of a node and it also likes to create data nodes when you parse a document. When printing, the data node takes precedence over the value.

When you create a document from scratch this likely won't bite you, but when you parse an existing document and neglect to supply the parse_no_data_nodes flag, the parser creates data nodes. If you try to update your values with the value() function, it works just fine (and you can even pull it back out without any problems), but when you use the print() function, the data node (which you haven't updated) will show up instead.

What made this even more difficult to track down was how value() will return the first data node it finds if there isn't a value yet, so it really does seem like you have a value already. I've updated my prior RapidXML entry to include the parse_no_data_nodes flag, which may save someone some time down the road.

Comments

shared_ptr is great...but sometimes auto_ptr is actually better!

— richardwb on Saturday, March 21, 2009 @ 18:04

Modern C++ programming benefits greatly from smart pointers. Smart pointers automate the error-prone process of making sure you have a matching number of new and delete statements. There's even one included in the C++ standard library: std::auto_ptr.

It's not a true general purpose smart pointer, however. For one, it has somewhat unusual transfer-of-ownership semantics:

std::auto_ptr<MyClass> a(new MyClass());
std::auto_ptr<MyClass> b = a;
// a now points to nothing!

This also makes it dangerous to use in containers, as described in Using auto_ptr Effectively. On the other hand, shared_ptr (which will be available in the next C++ standard, C++0x, and is now available in the Boost libraries) is a reference counting smart pointer. It keeps track of the number of references to a particular object, and when there are no more references, it deletes the object. This is safe to use in containers. In fact, you can use shared_ptr pretty much everywhere and you will never have to worry about manually releasing memory again (cycles and threading are pretty much the only major problems).

However, while shared_ptr is a great general purpose smart pointer, auto_ptr has its uses. If you have a function that involves transfer-of-ownership semantics (whether receiving or giving), why not use the smart pointer that perfectly captures those requirements? The 'sources' (creates and then gives away ownership) and 'sinks' (takes ownership) described in the Using auto_ptr Effectively article is a prime example of this. Instead of using comments to specify that the caller of a function must manage the lifetime of the returned object, auto_ptr forces them to manage it (and if they don't, it'll clean itself up anyway). shared_ptr will likely work just as well, but it doesn't capture the semantics.

Another noteworthy reason to use auto_ptr when the semantics are suitable is that while auto_ptr can give away ownership to shared_ptr, shared_ptr cannot give away ownership to auto_ptr or another smart pointer (there is no release() function in shared_ptr).

auto_ptr is on its way to deprecation, but we haven't even seen C++0x yet, so I wouldn't worry too much about it. Its replacement, unique_ptr, will have the same transfer-of-ownership semantics, just implemented in a much safer way, so it'd be worth the effort to get used to using the right smart pointer for the job.

Speaking of which, do you know what scoped_ptr is?

Comments