Saturday, April 2, 2011

Closure

  1. We want to wrap an arbitray block of code, passing it around and execute it somewhere.
  2. We want that block of code still has access to it's lexical environment, name lookup still works as if it's executed where it is defined.

Saturday, March 26, 2011

Smart pointers in Qt: QScopedPointer

There're several smart pointers in Qt, among which QScopedPointer and it's pal QScopedArrayPointer are probably the most simple yet useful ones.
QScopedPointer is similar to std::auto_ptr which provides a nice way to do RAII. The most common place to use this kind of smart pointer is in a function with multiple exit points. There's a nice example in the Qt document demostrating these scenarios.

Now let's take a look at their codes and try to find something interesting :)
First, the overiew of QScopedPointer looks like this:

template <
    typename T,
    typename Cleanup = QScopedPointerDeleter<T>
>
class QScopedPointer
{
public:
    explicit inline QScopedPointer(T *p = 0);
    inline ~QScopedPointer();
    // ...
protected:
    T *d;
};
As a smart pointer these are the two operators you are definitely going to overload:
inline T &operator*() const
{
    return *d;
}

inline T *operator->() const
{
    return d;
}
Note that the operator arrow is a little bit unusual, it works in this way:
// assume Foo has a member named "action"
QScopedPointer pointer(new Foo());

pointer->action(); // equivalent to (pointer->action)()
// thus same as ((pointer.operator->())->action)()
There's no explicit parameter for operator arrow (it's not really possible, the right hand "parameter" of operator arrow, "action" in the above case, is an identifier instead of an expression).
In a word, the operator arrow is applied recursively when the underlying object has an operator arrow. The procedure ends once the builtin operator arrow could be used (the underlying object is a pointer to a class object which has a member named "action").
It's like the "->" is not eaten up until it meets the "appropriate" "real" pointer :-)

Next let's take a look at the cleanup handler:

static inline void cleanup(T *pointer)
{
    typedef char IsIncompleteType[sizeof(T) ? 1 : -1];
    (void) sizeof(IsIncompleteType);
    delete pointer;
}
The weird sizeof is to cause a compilation error when the type T is incomplete, essentially the same as boost::checked_delete.
The C++ standard says, in 5.3.5/5, "If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined". So without these weird stuffs we'll need a responsible compiler which generates a warning message in the case of an incomplete type and a responsible programmer who doesn't ignore those messages.

Another thing you might notice is that there's no assign operator from T* to QScopedPointer and no convertion operator from QScopedPointer back to T*.
For the first operator there's a "reset" function which hopefully could remind you that you are deleting the old pointer while assigning a new one.
For the second operator you can use the "take" function which means you're taking the owner ship out of the QScopedPointer. The following codes illustrate the reason:

Foo *badBar()
{
    QScopedPointer<Foo> p(new Foo());
    // ...

    // calls the convertion operator (assuming there's one)
    return p;
    // but hey, the object is deleted when we leave the scope :(
}
Foo *goodBar()
{
    QScopedPointer<Foo> p(new Foo());
    // ...
    return p.take(); // ok, QScopedPointer is no longer in charge
}

QScopedArrayPointer is just a simple refinement of QScopedPointer specifically designed for array, as it's name suggests. It overloads the operator[] for convenient.
In addition to these operators there's just a few lines playing with template partial specialization and SFINAE to make sure the type in the template argument is the same as the one you pass to the constructor. Check it out in it's code if you're interested :P

Ok, this is pretty much it, enjoy programming :)

Tuesday, March 8, 2011

eBattery -- A pure simple battery monitor plasmoid

Well this actually starts when I removed polkit & consolekit from my system, and as udisks & upower depends on polkit, they are also removed. The reason why I removed them is that I already have sudo (with a config file I know exactly where it is and how to change it as I need) so I do not want another different and complex mechanism. As for udisks there's another reason: it pulls in lvm2 which is entirely useless to me.

Without upower (and without hal of course), KDE's batter monitor doesn't work anymore as hal and upower are the only backends KDE's powermanagement supports. So I write this simple plasmoid to display an icon in the system tray showing the status of the battery. It is based on sysfs interface so there's no dependency on any fancy power management backend. It looks just like the default battery monitor except that there's no interactive feature, it's just an icon :)

Download it here and run "plasmapkg -i ebat.plasmoid" to install.

Note that it only works with single battery cause I don't have any computer with multiple batteries to test it, but feel free to modify it if you need that feature as it's written in javascript and is really simple :)

Saturday, May 1, 2010

Hello world

Well, this is the beginning of this blog :-P