Qt 容器的隱式共享
|
|
Qt的線上文件中提及,Qt的容器類別(Container class)實作了隱式共享(implicit sharing),可以避免某些情況(像是唯讀)下的物件深層複製(deep copy),有助效率的改進,乍看之下,似乎不容易明白其中的意思,自己寫了幾個範例,應該有助於了解。
Qt的容器類別的隱式共享機制,又稱之為copy on write,顧名思義,就是在資料有變動的情況下,才進行容器內資料結構物件之複製,否則容器內資料結構物件是共享的。
舉個例子來說,如果您使用[]運算子方式,則會進行容器內資料結構物件之複製:
QList<QString> list1;
list1 << "x";
QList<QString> list2 = list1;
cout << &list1[0] << endl;
cout << &list2[0] << endl;
list1 << "x";
QList<QString> list2 = list1;
cout << &list1[0] << endl;
cout << &list2[0] << endl;
在上例中,使用了[]運算子,list1與list2內部的資料結構物件經過複製,並不是共享的,所以顯示出來的兩個記憶體位址並不相同,但使用at()時的情況則是相同的:
QList<QString> list1;
list1 << "x";
QList<QString> list2 = list1;
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
list1 << "x";
QList<QString> list2 = list1;
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
所以在唯讀的情況下,建議使用at()方法而不是[]運算子的方法,以避免容器內部資料結構物件複製的成本,藉以獲得較好的效率。
隱式共享又稱之為copy on write,是因為在容器中的資料有變動時,就不再共享內部資料結構物件,可以從下面的程式碼看出:
QList<QString> list1;
list1 << "x";
QList<QString> list2 = list1;
// 以下兩行顯示相同的記憶體位址
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
// 對 list2 作變動
list2 << "y";
// 以下兩行顯示不同的記憶體位址
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
list1 << "x";
QList<QString> list2 = list1;
// 以下兩行顯示相同的記憶體位址
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
// 對 list2 作變動
list2 << "y";
// 以下兩行顯示不同的記憶體位址
cout << &(list1.at(0)) << endl;
cout << &(list2.at(0)) << endl;
Qt容器的隱式共享機制之一,讓您可以用較簡明的方式來撰寫程式,例如您可以如下撰寫一個函式:
QList<QString> doSomething() {
QList<QString> list;
// ...blah..blah
cout << &list << endl;
return list;
}
QList<QString> list;
// ...blah..blah
cout << &list << endl;
return list;
}
然後就直接如下撰寫程式以利用這個函式,但不會進行物件複製:
QList<QString> list = doSomething();
cout << &list << endl;
cout << &list << endl;
上面的程式碼片段,在doSomething()中的list位址與呼叫doSomething()中list的位址會是相同的。無論是Java風格或STL風格的迭代器,使用唯讀迭代器時,背後也都會使用到隱式分享機制,以增加循序讀取的效率。
想幫您補充一下
等號(=)在QT裡被用來做指標參考而已,這個動做叫shallow copy,它是一種reference,當有一個物件被參考時,它有一個計數會記錄,記錄著有誰參考,所以它比較快,QT的文件被也提到這種行為在多執行緒時也可以運做的很好
而另一種真實的複製叫deep copy,這會真實的使用到一段大小的記憶體,當然這個動作就會比較花cpu和memory
看了一下您的網誌,寫得不錯....加油!!
由...發表 北鼻存錢筒 on 三月 27, 2008 at 01:22 下午 CST #
感謝。。Orz
由...發表 良葛格 on 三月 27, 2008 at 04:05 下午 CST #