簡體   English   中英

我可以重新解釋std :: vector <char> 作為std :: vector <unsigned char> 沒有復制?

[英]Can I reinterpret std::vector<char> as a std::vector<unsigned char> without copying?

我有一個std::vector<char>的引用,我想用它作為接受std::vector<unsigned char>的函數的參數。 我可以不復制嗎?

我有以下功能,它的工作原理; 但我不確定副本是否真的發生 - 有人可以幫助我理解這個嗎? 是否可以使用std::move來避免復制或者它是否已被復制?

static void showDataBlock(bool usefold, bool usecolor,
            std::vector<char> &chunkdata)  
{
  char* buf = chunkdata.data();                      
  unsigned char* membuf = reinterpret_cast<unsigned char*>(buf); 
  std::vector<unsigned char> vec(membuf, membuf + chunkdata.size()); 
  showDataBlock(usefold, usecolor, vec);   
} 

我以為我可以寫:

std::vector<unsigned char> vec(std::move(membuf),
                               std::move(membuf) + chunkdata.size());  

這有點矯枉過正嗎? 究竟發生了什么?

...是否可以使用std :: move來避免復制,或者它是否已被復制

您不能在兩個不相關的容器之間移動。 std::vector<char> 不是 std::vector<unsigned char> 因此,沒有合法的方法在O(1)時間內一個內容“移動〜轉換”到另一個內容。

你可以復制:

void showData( std::vector<char>& data){
    std::vector<unsigned char> udata(data.begin(), data.end());
    for(auto& x : udata)
        modify( x );
    ....
}

或者為每次訪問實時投射......

inline unsigned char& as_uchar(char& ch){
    return reinterpret_cast<unsigned char&>(ch);
}

void showDataBlock(std::vector<char>& data){
    for(auto& x : data){
        modify( as_uchar(x) );
    }
}

我猜你編碼了另一個重載函數: -

showDataBlock(usefold, usecolor, std::vector<unsigned char> & vec);  

您嘗試從std::vector<T>轉換為另一個std::vector<T2>

沒有辦法避免復制

每個std::vector都有自己的存儲空間,粗略地講,它是一個原始指針。
重點是:你不能在多個std::vector共享這樣的原始指針。
我認為這是設計的。
我認為這是一件好事,否則會浪費CPU來跟蹤。

編碼 ...

std::move(membuf)

...移動原始指針=實際上什么都不做。 (與傳遞為membuf相同)

要進行優化,您應該驗證原因:首先要將std::vector<char>轉換為std::vector<unsigned char>

如果你創建一個可以表示charunsigned char的新類C ,這是一個更好的主意嗎? (例如C::getChar()C::getUnsignedChar() ,可能是......只存儲char但提供轉換器作為其非靜態函數)

如果它沒有幫助,我建議創建一個新的自定義數據結構。
我經常在需要時這樣做。

但是,在這種情況下,我認為不需要任何優化。
對我來說沒關系,除非它是性能關鍵代碼。

如果你有一個類型為std::vector<T1>v1並且需要一個類型為std::vector<T2>v2 ,那么即使T1和T2像charunsigned char一樣“相似”,也無法復制數據。 。

使用標准庫:

std::vector<unsigned char> v2;
std::copy(v1.begin(), v1.end(), std::back_inserter(v2));

唯一可行的方法是以某種方式只使用一種類型:如果可能的話,從一開始就獲取std::vector<T2> ,或者從現在開始使用std::vector<T1> (可能會添加一個超載用它)。 或者創建可以處理任何[contigous]容器的通用代碼(模板)。


我認為reinterpret_cast和std :: move應該可以避免復制
不,它不能
請詳細說明 - 為什么不呢?

矢量可以僅從相同類型的另一個矢量中竊取資源(移動數據)。 這就是它的界面設計方式。

要做你想做的事,你需要一個release()方法,它將釋放底層數據的向量所有權並將其作為(唯一)指針和移動構造函數/賦值返回,它將從(唯一)指針獲取底層數據。 (即便如此,你仍然需要一個reinterpret_cast ,這是......危險區域)

std::vector沒有這些。 也許應該有。 它只是沒有。

正如其他人已經指出的那樣,如果不改變showDataBlock ,就無法繞過副本。

我想你有兩個選擇:

  1. 擴展showDataBlock以處理signed charunsigned char (即使其成為模板)或
  2. 不要將容器作為參數,而是使用迭代器范圍。 然后,您可以(在value_typechar情況下)使用特殊迭代器從signed char轉換為unsigned char元素。

unsigned charchar是不相關的類型。 我認為它們在這種情況下(相同大小的pod)足夠相似,以逃避整個模板類的reinterpret_cast。

static void showDataBlock(bool usefold, bool usecolor,
            std::vector<char> &chunkdata)  
{
  showDataBlock(usefold, usecolor, reinterpret_cast< std::vector<unsigned char>&>(chunkdata));   
}

但是,我傾向於發現這些問題是由於沒有設計出最好的架構。 看看這個軟件應該做的更大的圖片,以確定為什么你需要使用有符號和無符號的char數據塊。

我最終做了這樣的事情:

static void showDataBlock(bool usefold,bool usecolor, std::vector<char> chunkdata)
{                                                                                                                           
    std::vector<unsigned char>&cache = reinterpret_cast<std::vector<unsigned char>&>(chunkdata);                                              
    showDataBlock(usefold, usecolor, cache);    
}                                                                             

static bool showDataBlock(bool usefold,bool usecolor, std::vector<unsigned char> &chunkdata)   
{
    // showing the data
}

這個解決方案允許我傳遞矢量作為參考或正常它似乎工作 - 如果它是我不知道的最佳解決方案,但是你們都帶來了一些非常好的建議 - 謝謝大家

我同意我無法避免副本,所以我讓副本通過正常參數傳遞完成

如果您發現此解決方案有誤,請在評論中提供更好的解決方案,而不僅僅是downvote

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM