This is a repost from my previous Qt learning series, based on Qt 4.3.

    之前的笔记: QT4学习笔记 (1). 可以复习一下, 修改了一些错误.
    今天主要说一下Qt的实现, 主要是内存方面. 书上没有写, 完全是自己看源码的, 版本4.3.3 commercial.

    先来还是那段最简单的Qt代码:

    吐了没?= =b.. 还是那个new出来的QLabel的问题, Qt到底怎么样来回收的呢? debug的时候, 我直接把断点设在了QObjectQWidget类的析构函数(直接用debug模式, 打开源码设断点运行就行了). 事实证明还不够. 通过看call stack, 最终发现析构的过程从QApplication这个类开始的.
    /src/gui/kernel/qapplication.cpp, 析构函数中, 有这么一段:

    可能有点难懂, 反正大写Q开头的都是类名. 这段意思大概就是QApplication类会维护一个所有运行中QWidget的mapper, 以便析构函数中作相应处理. 这里似乎只看到调用QWidgetdestory()函数, 没有释放内存. debug的结果也验证了, QLabel的析构函数没有被调用到. 难道Qt不具备防止memory leak的么?
    我们改一下代码, 把heap内存改成stack内存:

    这个显然是没有问题的. 那我们应该怎么用Qt, 才能利用Qt自带的memory管理功能, 只管new, 不用自己delete呢? 再看一段代码:

    (以上sb代码debug之用, 切勿模仿…)
    我们在QDialog上加了一个QLabel, QDialog是在stack上创建的. debug中, 当QDialog对象调用析构函数时, 在/src/gui/kernel/qwidget.cpp中, 会调用QWidget的析构函数. 在QWidget的析构函数中, 有这样一段:

    d是什么东西? 继续跟进, 发现d是一个QObjectPrivate类的对象, 其中的确有delete的操作(废话, 老子依据call stack反推的啊). 于是我们清楚了, Qt的类之间有父子关系(这里指的是包含, 而不是继承关系), 一旦父类对象被被delete的话, 子类也会被相应的delete. 所以, Qt中我们一般都不需要调用delete的. 但是有一个前提: 由于deleteChildren()函数是QObjectPrivate类的函数, 要使以上条件成立的话, 所有的包含关系的类必须都继承自QObject. 这里有一个design pattern, composite, 嗯.
    另外有一点, QObject类没有定义拷贝构造函数, 也就是说一般的赋值都是shadow copy. 其实是有道理的, 当我们copy一个QObject的时候, 新的object到底是继承原来的children还是不继承呢? 呵呵.
    最后我们再来花点时间讨论一下QObjectQObjectPrivate类的关系. 在/src/corelib/global/qglobal.h中, 有以下代码:

    额.. 也就是说, 一般QXxx类和QXxxPrivate类互为friend类, 一般来说QXxxPrivate类都是一些底层实现, 不属于对外的Qt API. 而QXxx类则是对外的Qt API. 有比如说有QProcessQProcessPrivate两个类, 在/src/corelib/io下, 对应4个文件, qprocess.h, qprocess.cpp, qprocess_p.h, qprocess_win.cpp. 前2个是对外的Qt API, *_p.hQProcessPrivate类头文件, *_win.cpp则是对应的平台相关的实现代码.

    好了, 下班了, 明天再写…

This is a repost from my previous Qt learning series, based on Qt 4.3.

    为什么要学这个? 主要是学习其中的design pattern.
    丸子买不起书, 所以看的是电子版: C++ GUI Programming with Qt4, 2nd Edition

    作为一个跨平台的GUI库, 首先Qt用的design pattern是facade模式: 不管subsystem如何, 对外提供简单统一接口.
    跟wxWidgets一样, 每次你new出来的widget其实都是不用自己来delete的, Qt会自己帮你delete掉. 可以参看源码: /src/gui/kernel/qwidgets.cpp 中的析构函数. 注意如果你用MFC的话, memory是要你自己搞定的.
先来看一段最简单的Qt代码:

    诶.. 你发现既然是GUI的程序, 为什么用的入口函数是main(), 而不是WinMain()? 能看出这个问题你已经有相当的水平了. 其实Qt自己写了一个WinMain(), 在里面调用你的main(). 源码在这里可以找到: /src/winmain/qtmain_win.cpp (windows版本).
接下来再看一个稍微复杂一点的:

    于是你看到了Qt的事件处理机制signal/slot (信号? 插槽? 好x啊–b). 一个signal相当于一个event, slot相当于一个handler. signal和slot可以是多对多的关系. 其实这里包含了两个dessign pattern. observer模式显而易见, 还有一个就是mediator模式. 这样说应该懂了吧, 不懂的话请翻阅我之前写的design pattern系列的文章.
    另外, 可以参考Qt的官方文档: Signals and Slots. 上面大概说了这么几点重要的:
a) signals/slots/emit实际上都是macro(可以看源码). 对于c++ compiler来说, signals–>protected, slots–>nothing, emit–>nothing, 对于moc(这个工具下面会说)来说, 则被另外不同的preprosessor机制预处理.
b) 通过signal/slot可以调用private的slot(这个我没试过..不太好吧).
c) SIGNAL/SLOT宏, 这2个东西很搞, 实际上就是在函数名前加上”1″或者”2″结成新的字符串–b. 所以, 丸子觉得, 这里可能是不安全的, 如果拼错了的话编译器也是检查不出来的.
d) Q_SIGNALS/Q_SLOTS/Q_EMIT宏有特殊意义, 用于第三方的signal/slot机制避免冲突.
e) signal/slot的函数signature必须: *) 相同. *) 或者slot的参数比signal要少.
    最后, 你看到一个QButton自己show()就可以了. 没错, 因为QButton继承QWidget, QWidget都是可以直接show()的, 这点跟其他的GUI Kit不一样.
    这里有2个工具: moc(Meta-Object Compiler), uic(User Interface Compiler).
    moc用来维护Qt中类的运行时信息, 把它想象成Java中的reflection就可以了. 那么麻烦主要是由于C++本身不支持这个. 所以, 实际上signal/slot机制的实现也用到了这些信息, 因此一个Qt类一定要实现某些特定的接口函数, 这就是moc所做的工作了.
    uic用来把*.ui文件转化成C++代码, 以便能编译到一个binary中去. 用xml做ui真的是一个很不错的想法, 不过这里有一个问题啊. 那就是用uic生成C++代码之前, 其它C++类如果要引用ui中的成员变量似乎是不可能的. 诶.. 这个不知道怎么解决.

    つつく.

This is a quick note to chapter 4 of C++ Concurrency in Action.

1. std::thread

In C++11, It’s quite simple to create a separate thread using std::thread. Following code will simply output “hello world” or “world hello”:

2. std::mutex and std::condition_variable

If you need synchronization between threads, there are std::mutex and std::condition_variable. The semantics are the same with that in pthread library. Here’s a simple producer/consumer demo:

3. std::future with std::async()

C++11 also simplifies our work with one-off events with std::future. std::future provides a mechanism to access the result of asynchronous operations. It can be used with std::async(), std::packaged_task and std::promise. Starting with std::async():

std::async() gives two advantages over the direct usage of std::thread. Threads created by it are automatically joined. And we can now have a return value. std::async() decides whether to run the callback function in a separate thread or just in the current thread. But there’s a chance to specify a control flag(launch::async or launch::deferred) to tell the library, what approach we want it to run the callback.

When testing With gcc-4.8, foo() is not called. But with VC++2013, it does output “hello”.

4. std::future with std::packaged_task

With std::async(), we cannot control when our callback function is invoked. That’s what std::packaged_task is designed to deal with. It’s just a wrapper to callables. We can request an associated std::future from it. And when a std::packaged_task is invoked and finished, the associated future will be ready:

In waiter() and waiter2(), future::get() blocks until the associating std::packaged_task completes. You will always get “in pt” before “after f.get()” and “in pt2” before “after f2.get()”. They are synchronized.

5. std::future with std::promise

You may also need to get notified in the middle of a task. std::promise can help you. It works like a lightweight event.

Future and Promise are the two separate sides of an asynchronous operation. std::promise is used by the “producer/writer”, while std::future is used by the “consumer/reader”. The reason it is separated into these two interfaces is to hide the “write/set” functionality from the “consumer/reader”:

Again in waiter() and waiter2(), future::get() blocks until a value or an exception is set into the associating std::promise. So “setting p” is always before “f.get()” and “setting p2” is always before “f2.get()”. They are synchronized.

NOTE: std::future seems to be not correctly implemented in VC++2013. So the last two code snippet do not work with it. But you can try the online VC++2015 compiler(still in preview as this writing), it works.

This is a quick note to C++ Templates: The Complete Guide. Name Taxonomy comes first in chapter 9:

Qualified name: This term is not defined in the standard, but we use it to refer to names that undergo so-called qualified lookup. Specifically, this is a qualified-id or an unqualified-id that is used after an explicit member access operator (. or ->). Examples are S::x, this->f, and p->A::m. However, just class_mem in a context that is implicitly equivalent to this->class_mem is not a qualified name: The member access must be explicit.

Unqualified name: An unqualified-id that is not a qualified name. This is not a standard term but corresponds to names that undergo what the standard calls unqualified lookup.

Dependent name: A name that depends in some way on a template parameter. Certainly any qualified or unqualified name that explicitly contains a template parameter is dependent. Furthermore, a qualified name that is qualified by a member access operator (. or ->) is dependent if the type of the expression on the left of the access operator depends on a template parameter. In particular, b in this->b is a dependent name when it appears in a template. Finally, the identifier ident in a call of the form ident(x, y, z) is a dependent name if and only if any of the argument expressions has a type that depends on a template parameter.

Nondependent name: A name that is not a dependent name by the above description.

And the definition from Chapter 10:

This leads to the concept of two-phase lookup: The first phase is the parsing of a template, and the second phase is its instantiation.

During the first phase, nondependent names are looked up while the template is being parsed using both the ordinary lookup rules and, if applicable, the rules for argument-dependent lookup (ADL). Unqualified dependent names (which are dependent because they look like the name of a function in a function call with dependent arguments) are also looked up that way, but the result of the lookup is not considered complete until an additional lookup is performed when the template is instantiated.

During the second phase, which occurs when templates are instantiated at a point called the point of instantiation(POI), dependent qualified names are looked up (with the template parameters replaced with the template arguments for that specific instantiation), and an additional ADL is performed for the unqualified dependent names.

To summarize: nondependent names are looked up in first phase, qualified dependent names are looked up in second phase, and unqualified dependent names are looked up in both phases. Some code to illustrate how this works:

Now look into Derived::foo(). I is a nondependent name, it should be looked up only in first phase. But at that point, the compiler cannot decide the type of it. When instantiated with Derived<bool>, I is type int. When instantiated with Derived<void>, I is type double. So it’s better to look up I in the second phase. We can use typename Base<T>::I i = 1.024; to delay the look up, for I is a qualified dependent name now.

Unfortunately, two-phase lookup(C++03 standard) is not fully supported in VC++ even in VC++2013. It compiles well and gives your most expecting result(output 1 and 1.024). With gcc-4.6, it gives errors like:

Another code snippet:

When the compiler sees f(), g() has not been declared. This code should not compile, if f() is a nontemplate function. Since f() is a template function and g() is a nondependent name, the compiler can use ADL in first phase to find the declaration of g(). Note, a user-defined type like Int is required here. Since int is a primitive type, it has no associated namespace, and no ADL is performed.

VC++2013 still compiles well with this code. You can find some clue that they will not support it in the next VC++2015 release. With gcc, they declared to fully support two-phase lookup in gcc-4.7. I used gcc-4.8, error output looks like:

And the code compiles well with self-defined type Int(using -D_USE_STRUCT switch).

Following the last post, I’m trying to implement a thread pool for practise, which supposed to work under both Windows and Linux platform. But the different semantics between Win32 events and condition variables makes it impossible to code in a unified logic. First, Linux uses mutex and condition variable to keep synchronization. While there is only event under Windows. Then, pthread_cond_signal() does nothing if no thread is currently waiting on the condition:

But under Windows, code below simply pass through:

And, under Windows Vista and later versions, a new series of synchronization API was introduced to align with the Linux API: