2011-03-09 36 views
4

我試圖避免重新實現我自己笨拙的版本的標準算法,因此正在玩標準庫版本。由於我不是C++的專家,因此我謹慎行事,開啓全面的調試選項。使用C++標準庫算法與valarray

具體而言,我在valarray容器上使用二分查找。下面的代碼塊似乎產生正確的結果,並且valgrind不會抱怨。儘管如此,我確實感到我處於一個滑坡,因爲我不確定我所做的事情是否真的被允許,或者我只是被編譯器放出去了。

代表性的一段代碼:

#include <iostream> 
#include <valarray> 
#include <algorithm> 
#include <typeinfo> 

using namespace std; 

int main(){ 

valarray<double> v(10); 
for (int i=0 ; i<10 ; ++i){ 
    v[i]=2. *i ; 
    cout<<v[i]<<" "; 
} 
cout << "\n"; 

double what=17; 
double* it=lower_bound(&v[0], &v[10],what) ; 

cout<<it-&v[0]<<" "<<typeid(&v[0]).name()<<" "; 
cout<<typeid(it).name()<<" "<<typeid(it-&v[0]).name()<<"\n"; // ??? 

int idx=it-&v[0]; 
cout<<"v["<<idx<<"]="<<v[idx]<<"\n"; 
} 

問題:

  1. 是我在這裏做什麼真的合法嗎?
  2. 兩個指針變爲double的區別是什麼? (符合???評論)
  3. 類型轉換的開銷是多少? --- I am與效率有關,因爲這種功能將會佔用佔用90%以上計算時間的代碼部分。
+0

我修復了我的答案,不完全錯誤,我認爲它也是完整的。 – Omnifarious 2011-03-09 01:35:49

回答

2
  1. 您使用的int索引到valarray。這個例子是有效的,但不是一般的。使用std::size_t來索引valarray。 (這同樣適用於std::vector和普通陣列。)

  2. 於任何類型的兩個指針之間的差異是未指定的整數類型的,可能intlong和總是足夠小以適合在std::ptrdiff_t

  3. 轉換哪個?

+0

哎呀,謝謝!這是我正在使用的特定版本的gcc的功能,還是這是便攜式? – 2011-03-09 01:15:44

+0

@振亞:正如我所說(在編輯後),未指定。如果要存儲兩個指針之間的差異,請始終使用'ptrdiff_t'。 – 2011-03-09 01:19:00

+0

我個人更喜歡使用索引[畢竟它是一個固定大小的數組],但'lower_bound'想要返回一些迭代器。但是,只要它是一個整數類型,我認爲它可以安全地用作索引。感謝您的澄清! – 2011-03-09 01:29:34

1

我相信這是所有定義的行爲,將繼續在任何實現上工作。看看valarray的各種文檔,看起來它必須是合法的,才能使::std::valarray的所有其他內容保持正確。在調用resize成員函數或valarray被銷燬之前,指向元素的裸指針應保持完全有效。

唯一真正的問題是valarray是否需要連續或不連續地保持其元素。我發現了answer to that question in a post。我會在這裏摘錄它:

是的,valarray也使用連續的 存儲。從 標準的特定措辭($ 26.3.2.3/3):將 表達&一個[I + J] == & A [1] + J 所有的size_t評估爲真i和 爲size_tĴ使得i + j小於 非常數陣列的長度爲 a。

當然,切片仍然不能直接與標準算法一起使用,儘管創建切片迭代器不應該太難。創建一個雙向訪問迭代器會非常容易,但要難得多(需要很多棘手的數學手段才能完全正確)才能創建一個隨機訪問迭代器。

兩個指針之間的區別變成(如別人所說)::std::ptrdiff_t。這將是不同平臺上的不同類型。我使用64位Fedora 14下的gcc,對我來說類型是long。這種「類型轉換」沒有開銷。它甚至不是真正的轉換。編譯器只是進行減法,就好像兩個指針是普通的舊數字一樣,結果是某種類型的普通舊數字。這種類型的使用::std::ptrdiff_t是爲了確保使用的數字類型足夠大,以保持系統中任何兩個指針之間的差異。

+0

謝謝!我知道'valarray'在記憶中是連續的[這就是爲什麼我首先使用];我確實需要隨機訪問,因爲索引很好。正是這個指向整數的對應讓我感到困惑。 – 2011-03-09 09:54:31

0

這些it-&v[0]真的嚇到我..你的意思是it->v[0]? lower_bound的返回值類型爲valarray<double>::iterator,請使用該值代替double*!所有其他解除重複問題將自動消失。例如,您可以執行*itit++,但不能執行it->v[0],因爲它不是指針而是迭代器。它很可能是一個導致你所有的企圖非法獲取其價值的引擎。在迭代器

更多信息:http://www.cppreference.com/wiki/iterator/start

編輯:哦,現在我明白了,你正在使用嚇人指針運算!這是如此C,我們不再這樣做;)

+1

valarray不支持迭代器。 – 2011-03-09 01:19:04

+0

@ Zhenya valarray支持C++ 11中的迭代器 – 2014-08-30 13:01:38