原文出处:blog.qt.digia.com/cn/2011/08/22/cpp0x-in-qt c++
咱们前面介绍了许多 C++ 11 的优势,并且介绍了如何在 Qt 5 中使用 C++ 11。可是,Qt 5 毕竟只是一个还没有发布的版本,如今,咱们要介绍的是,如何在 Qt 4 中使用 C++ 11。 函数
如今,咱们能够在 Qt 4.7 和 4.8 两个版本中使用 C++ 11。4.8 则增长了更多关于 C++ 11 的支持。 性能
若是编译器支持新的特性,Qt 提供了许多新的宏: this
Language: C++ (Qt) | |
0 1 2 3 4 5 6 7 8 9 |
Q_COMPILER_RVALUE_REFS Q_COMPILER_DECLTYPE Q_COMPILER_VARIADIC_TEMPLATES Q_COMPILER_AUTO_TYPE Q_COMPILER_EXTERN_TEMPLATES Q_COMPILER_DEFAULT_DELETE_MEMBERS Q_COMPILER_CLASS_ENUM Q_COMPILER_INITIALIZER_LISTS Q_COMPILER_LAMBDA Q_COMPILER_UNICODE_STRINGS |
Qt 4.8 为 QVector、QList 和 QStringList 增长了新的构造函数,容许咱们使用 C++ 11 提供的初始化器进行初始化。例如: spa
QVector<int> data {1, 2, 3, 4, 5}; QStringList ops = { QLatin1String("foo"), QLatin1String("bar") };
Qt 提供了许多隐式共享类。这意味着,若是你没有修改它们,那么复制操做将会是很高效的(写时复制)。这些操做对于 std::vector 是无效的,复制 std::vector 会复制全部数据。若是,若是你的代码相似这样: .net
Language: C++ (Qt) std::vector<int> m_foo; // ... m_foo = getVector();
getVector() 函数可能须要构造一个新的 std::vector,将其复制给一个临时变量,而后 std::vector::operator= 运算符则须要销毁旧的 m_foo,再将这个临时变量中的所有数据复制到 m_foo。当这条语句结束时,这个临时的 vector 将会被销毁,它的析构函数会删除其全部数据。若是 operator= 简单地将 m_foo 的数据切换到这个临时变量的数据,无疑会使这个操做更高效。这样的话,m_foo 的旧数据要在这个临时变量销毁时才去 delete,这就减小了没必要要的复制。这就是 C++ 11 的移动语义,它是由右值引用实现的。 code
即便复制隐式共享的类代价并不昂贵,但也并不意味着没有代码,咱们依然要增长和减小引用计数,调用 operator= 也不能是 inline 的(由于它得访问 private 数据,为了二进制兼容,咱们不能将其写做 inline)。下面,来看看 Qt 4.8 的 QImage 移动运算符: blog
Language: C++ (Qt) | |
#ifdef Q_COMPILER_RVALUE_REFS inline QImage &operator=(QImage &&other) { qSwap(d, other.d); return *this; } #endif |
咱们仅仅是交换了两个图像的内部数据,比起一般的操做,这样的操做已经很廉价了。在 Qt 中,大部分隐式共享类都是这么作的。既然全部容器都有大量的这种操做,那么将 operator= 按照移动语义定义,确定会提高 Qt 的性能。这也是使用 C++ 11 编译 Qt 的理由之一。 get
Qt 提供了一个很是方便的 foreach 宏。你也能够在其它 C++ 库,好比 boost 中找到相似的东西。Qt 的 foreach 仅仅是一个比较复杂的宏,C++ 11 则作得更多,将其做为语言的一部分。所以,像下面的代码: 编译器
Language: C++ (Qt) | |
0 |
foreach(const QString &option, optionList) { ... } |
咱们就能够写成
Language: C++ (Qt) | |
0 |
for(const QString &option : optionList) { ... } |
这两者仍是有一点区别的:Qt 在遍历以前将容器进行了复制。对于 Qt 容器,这是廉价操做,由于 Qt 容器都是隐式共享的,但对于标准库的容器,这样作会引起对整个内容的深拷贝。C++ 11 的 foreach 循环不须要复制。这意味着,若是你在遍历过程当中添加或者删除了容器的元素,所带来的后果是无定义的。
若是容器是共享的,而且不是 const 的,那么,若是你要支持 C++ 11 的新的 for,应该本身去调用容器的begin() 和 end() 函数,将容器复制一遍。所以,正确的代码应该是这样的:
Language: C++ (Qt) | |
|
template<class T> const T &const_(const T &t) { return t; } for(auto it : const_(vector)) { ... } |
又到了我最喜欢的部分了 ;-P
比起 Qt 5 来,Lambda 表达式在 Qt 4 中应用不是不少,仅仅是在 QtConcurrent 的某些函数中。
咱们如今能够在 QtConcurrent::run() 和 QtConcurrent::map() 中使用 Lambda 表达式:
Language: C++ (Qt) | |
QList<QImage> images = ... QFuture<void> future = QtConcurrent::map(images, [](QImage &image) { image = image.scaled(100,100); }); |
|
若是你正在使用 MSVC 2010,那就没什么好作的了。你彻底能够开始使用 C++ 11 的新特性,好比 Lambda 表达式和右值引用。
若是你使用的是 GCC,你须要增长 -std=c++0x 编译参数,而后在 .pro 文件中添加:
QMAKE_CXXFLAGS += -std=c++0x
若是你须要使用 C++ 11 编译 Qt,那么就使用:
CXXFLAGS="-std=c++0x" ./configure
Qt 将会以 C++ 11 编译,同时兼容旧的 C++ 代码。另外须要说明的是,若是你仅仅使用 C++ 11 编译本身的程序,是不须要使用 C++ 11 从新编译 Qt 的。
做者: 豆子 日期: 2012 年 06 月 21 日