原文出處: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 日