2015-11-02 61 views
3

std::uninitialized_copy複製到未初始化的內存範圍內。 這可以使用memmove來完成按位可複製類型。 我在gdb中使用下面的示例代碼(用gcc 5.2.0編譯)。因此我觀察到memmove根本沒有使用。爲什麼gcc在std :: uninitialized_copy中使用memmove?

在該示例中,用於確定是否可以使用memmove。 它(正確地)評估爲falseBar有一個非平凡的默認構造函數(參見調用std::__uninitialized_copy<false>::__uninit_copy(...)bits/stl_uninitialized.h123 ff)。 但爲什麼__is_trivial甚至與std::uninitialized_copy有關? 根據Bjarnestd::is_trivially_copyable應該足夠了。請注意,後者在該示例中評估爲true,即。 memmove優化is applicable

我知道,該標準不需要任何具體的實現std::uninitialized_copy。我只是想知道爲什麼__is_trivial更受青睞,即使std::is_trivially_copyable作爲適用於gcc實現的替代方案而存在?

示例代碼:

#include <iostream> 
#include <memory> 
#include <vector> 
#include <type_traits> 

struct Bar 
{ 
    Bar() : v(42) {}; 
    Bar(Bar const &) = default; 
    Bar(Bar &&) = default; 
    Bar & operator=(Bar &&) = default; 
    Bar & operator=(Bar const &) = default; 
    ~Bar() = default; 
    int v; 
}; 

int main() { 
    std::cout 
     << std::is_trivially_move_constructible<Bar>::value 
     << " " << std::is_trivially_copy_constructible<Bar>::value 
     << " " << std::is_trivially_copyable<Bar>::value 
     << " " << std::is_trivial<Bar>::value 
     << " " << __is_trivial(Bar) << std::endl; 
    size_t const num_elements = 1 << 27; 
    std::vector<Bar> v(num_elements); 
    Bar * vc = (Bar *) std::malloc(num_elements * sizeof(Bar)); 
    std::uninitialized_copy(v.begin(), v.end(), vc); 
    std::free(vc); 
} 

輸出示例:1 1 1 0 0

更新:我們做了一些測試,比較的memmoveuninitialized_copy實際運行時和一個簡單的for循環。如果Bar是微不足道的(參見),uninitialized_copymemmove一樣快,如果不是,uninitialized_copy與我們的for循環一樣快。總體上memmove僅在小Bars(即,將int v;更改爲char v;)上顯着更快(2x)。否則,表現基本相同。

編輯:正確引用std::is_trivially_...。更準確地說明州名稱。

+2

你正在混淆'is_trivially_copy_constructible'和'is_trivially_copyable'。 Bjarne的示例代碼使用第二個,而不是第一個。 – pmr

+2

這是真的,我糾正了這個問題。雖然'is_trivially_copyable'也評估爲'true',但問題仍然存在。 – m8mble

+0

您複製到未初始化的內存範圍。我解釋它的方式,不能有重疊(因爲一個是初始化的,另一個不是),所以你可以使用'memcpy'而不是'memmove'。 –

回答

0

對於將來的讀者:這已經作爲海灣合作委員會增強here提交。

相關問題