Back to Blog home

C++ 11在Qt 5中的应用

Published on 星期一 七月 09, 2012 by Cheng Liang in Qt Qt 5 qtearth-blogs-chinese | Comments

参考原文:woboq: Olivier Goffart - C++11 in Qt5

C++ 11现在已经是C++标准,也就没有理由不在新的应用中使用。

Qt 4.8是第一个支持C++ 11特性的Qt版本。我在4.8发布之前写过一篇博客——Qt中的C++0x,这里就不再重复了。

显而易见的是,比起Qt 4.8,Qt 5利用了更多的C++ 11新特性。下面我们来一个个见识一下:

槽中使用Lambda表达式

Lambda表达式是C++ 11带来的最激动人心的特性之一。简而言之,它允许创建匿名函数。匿名函数则允许我们直接将一个函数作为参数传递,无需显式地声明。

在此之前,使用利用operator()在结构体中实现仿函数需要很多技巧性代码。

Qt 4.8实际已经可以使用这个特性。只不过在Qt 4.8中,Lambda表达式只能用在QtConcurrent的某些函数。现在,前面我们也介绍过,Qt 5有Qt 5中新的信号/槽语法,Lambda表达式有了更大的用武之地。回忆一下,在你需要编写槽代码的时候,即使只有一条语句,你也必须为它单独建立一个函数。这不是很麻烦吗?现在,我们有了更好的写法:

connect(sender, &Sender::valueChanged, [=](const QString &newValue) {
receiver->updateValue("senderValue", newValue);
});

Lambda表达式现在已经被MSVC 2010、GCC 4.5和clang 3.1实现。

Unicode字符串常量

C++ 11允许你使用u"HelloWorld"的形式生成UTF-16字符串。Qt利用这个特性增加了一个新的类QStringLiteral。这个类能够在编译时初始化QString,没有了运行时的时间消耗。参考之前关于QStringLiteral的文章

QString str = QStringLiteral("HelloWorld");

常量表达式 constexpr

C++ 11增加了新的关键字constexpr,指示某些内联函数可以在编译期运算。在Qt 5中,我们引入了Q_DECL_CONSTEXPR宏,当所使用的编译期支持constexpr时,这个宏可以生成constexpr,否则的话则是空白。

在Qt源代码中,我们也利用这个宏改写了许多函数,例如:

enum SomeEnum { Value1, Value2, Value3 };

Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags<SomeEnum>)
// 上面一句声明了下述函数:
// Q_DECL_CONSTEXPR QFlags<SomeValue> operator|(SomeValue,SomeValue) {...}

int someFunction(QFlags<SomeEnum> value) {
switch (value) {
case SomeEnum::Value1:
return 1;
case SomeEnum::Value2:
return 2;
case SomeEnum::Value1 | SomeEnum::Value3:
// 这一个 case 仅在 C++ 11 中通过编译
// 因为 QFlags 运算符是 constexpr 的,也就是在编译期即可确定
// 而在之前版本则必须是
// QFlags<SomeValue> operator|(SomeValue,SomeValue)
// 这会引发一个错误,因为 case 语句要求编译期常量
return 3;
default:
return 0;
}
}

注意,这里我们在枚举值前面使用可SomeEnum::前缀,这是C++ 11允许的,但是之前版本的C++则不允许。

static_assert

在编译期使用static_assert检测问题,可以让C++ 11帮助我们可以组织处更好的错误信息。Qt 5引入了Q_STATIC_ASSERTQ_STATIC_ASSERT_X两个宏。当static_assert可用时,这两个宏将使用static_assert,否则使用一些模板技巧。

为了产生更好的编译错误信息,Qt在API不方便的地方大量使用了宏。

override和final

你遇到过这样的错误吗?自己定义的函数名看上去同父类的某个函数同名,但却的确有某些字母打错了,以至于并没有覆盖父类函数,从而让程序不能正确运行(或者是忘记了那函数名最后面的该死的const)?

现在,你可以选择在的确需要覆盖父类虚函数的地方加上Q_DECL_OVERRIDE。如果编译器支持的话,这个宏将展开为新增加的“override”关键字。这样的话,如果编译器支持C++ 11,那么如果是简单的字母错误,你就会得到一个错误;当你重构虚函数、却忘记修改子类时,同样会引发一个错误。

class MyModel : public QStringListModel {
//...
protected:
Qt::ItemFlags flags (const QModelIndex & index) Q_DECL_OVERRIDE;
};

注意,上面的flags()函数实际是想覆盖父类的同名函数,但是我们忘记了一个const,就会出现类似下面的错误:

mymodel.h:15: error: `Qt::ItemFlags MyModel::flags(const QModelIndex&)`
marked override, but does not override

如果虚函数不能覆盖,Qt也提供了另外一个宏,Q_DECL_FINAL,这个宏展开为final

deleted成员

当编译器支持deleted函数时,新增加的宏Q_DECL_DELETE将展开为=delete。这就允许我们能够为一些常见错误提供更好的编译器错误信息。

deleted函数用于显式地删除那些不允许编译器自动生成的函数(例如默认构造函数、默认拷贝运算符等)。deleted函数不能被调用,如果被使用的话,将会出现一个编译器错误。

我们可以将其用于Q_DISABLE_COPY宏。在此之前,为了实现同样的目的,我们的做法是将其声明为私有的。尽管效果相同,但是错误信息却并不友好。

右值引用和移动构造函数

在这里,我假定你明白什么叫做“右值引用”。如果不明白,我们会在后面的文章中详细说明。Qt 5已经在内部进行了调整,以便支持移动构造函数。因此,你可以大胆的使用它们了!

结论

对于C++ 11,MSVC不需要任何特殊的编译参数,而GCC和Clang则需要添加-std=c++0x

默认情况下,Qt 5本身会使用C++ 11编译参数进行编译(如果可能的话)。

如果你使用的是qmake,那么,在使用Qt 5构建的程序的.pro文件中,你需要增加这么一句:

CONFIG += c++11

(顺便提一句,在Qt 4中,如果你需要使用C++ 11的新特性,则应该增加gcc:CXXFLAGS += -std=c++0x。具体细节,我们会在后面的文章中说明。)

现在,好好利用C++ 11所带来的新特性吧!私以为,仅仅为了auto这一特性,就应该尽快使用C++ 11了!

Subscribe to Our Blog

Stay up to date with the latest marketing, sales and service tips and news.

Richard Thompson
0 points
38 months ago

The Qt 5.15 links are both dead, regardless of whether I'm logged in as commercial or not.

The dev and Qt 6.2 links only appear to refer to loading opengl32.dll or opengl32sw.dll, while this advisory mentions QLockFile and QAuthenticator and "LoadLibrary in a few locations" and gives opengl32.dll as an example.

Is there something missing from this blog post? The CVE is extremely vague (presumably intentionally)

Finally, "opengl32sw.dll" is not part of a normal Windows 7/8/10/11 installation. I believe this means this fix does not in fact correct the problem - a miscreant able to insert an evil dll into the application directory can also set the "force software rendering" environment or qt.conf, and thus require the use of their evil opengl32sw.dll.

A
Andy Shaw
0 points
38 months ago

Both links for Qt 5.15 are working fine for me at least, if you are still having problems then please contact us via the Support Center in Qt Account so we can just provide you the patches directly.

Qt 5.15 has a problem in QLockFile and QAuthenticator at least as well as in the windows plugin, but in Qt 6 it is only in one place where it is a problem. But since the cause is the same then it was covered as one inclusive post and CVE.

When Qt is deployed, then typically it will be deployed with opengl32sw.dll because the automatic loading of software rendering might trigger and as a result the application directory should be protected against this usage. Forcing software rendering can only be done via specific ways and those can be overridden by the application itself if that level of protection is needed here.

What I would recommend is discussing this with the support team if you need further clarification so they can go into further detail if needed.