在 Qt4 中使用 C++11

在 Qt4 中使用 C++11

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

foreach 循環

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)) { ... }

Lambda 表達式

又到了我最喜歡的部分了 ;-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 日

本文來自 DevBean's World: http://www.devbean.net
轉載時請標明文章原始出處: http://www.devbean.net/2012/06/cpp11-in-qt4/
相關文章
相關標籤/搜索