簡體   English   中英

為什么Microsoft std :: vector :: insert使用rotate()?

[英]Why does Microsoft std::vector::insert use rotate()?

我正在使用列表與向量進行一些實驗,我注意到std :: vector的Microsoft實現正在為.insert執行以下操作:

iterator insert(const_iterator _Where, _Ty&& _Val)
    {   // insert by moving _Val at _Where
    return (emplace(_Where, _STD move(_Val)));
    }

    iterator emplace(const_iterator _Where \
        COMMA LIST(_TYPE_REFREF_ARG)) \
    {   /* insert by moving _Val at _Where */ \
    size_type _Off = _VIPTR(_Where) - this->_Myfirst; \
    _VECTOR_EMPLACE_CHECK \
    emplace_back(LIST(_FORWARD_ARG)); \
    _STD rotate(begin() + _Off, end() - 1, end()); \
    return (begin() + _Off); \
    }

我無法弄清楚vs2012中的旋轉功能,但在2015年這樣做:

template<class _RanIt> inline
    _RanIt _Rotate(_RanIt _First, _RanIt _Mid, _RanIt _Last,
        random_access_iterator_tag)
    {   // rotate [_First, _Last), random-access iterators
    _STD reverse(_First, _Mid);
    _STD reverse(_Mid, _Last);
    _STD reverse(_First, _Last);
    return (_First + (_Last - _Mid));
    }

// TEMPLATE FUNCTION reverse
template<class _BidIt> inline
    void _Reverse(_BidIt _First, _BidIt _Last, bidirectional_iterator_tag)
    {   // reverse elements in [_First, _Last), bidirectional iterators
    for (; _First != _Last && _First != --_Last; ++_First)
        _STD iter_swap(_First, _Last);
    }

如果我們考慮緩存,這不是遍歷內存的最佳方式。

我做了一些基准測試,在那里我將元素保存在一個臨時元素中並使用它來交換元素,它更快:這就是它:

push_back(value); //My vector doesn't have resize/grow implemented
T tmp = *(end() - 1);
while(new_location != end())
{
    std::swap(tmp, *new_location);
    new_location++;
}

完整的代碼和測試在這里

第一個問題:

為什么它會旋轉而不是我在這里展示的第二版插入?

與第一個版本相比,第二個版本是更加緩存友好的替代版本。 對於大向量,與向量中的最后一個元素進行交換會由於高速緩存而引入時間損失。

是為了避免存儲另一個臨時的?

第二個問題:

為什么它不只是將元素記在右邊的一個位置?

是否有標准要求強制您交換元素而不是調用memmove? 有趣的是,對於POD而言,沒有一種特殊的模板專業化可以讓你記憶猶新。 在任何情況下,我更感興趣的是為什么旋轉而不是使用更多緩存友好的替代方案。

在我的測試中,這比前兩個版本更快。

測試完成如下:

0)對於i = 0來計數

1)在向量中選擇一個隨機位置

2)觸摸從0到該位置的每個元素(強制讀取它)

3)到達位置后調用插入

使用Visual Studio 2012 x86,/ O2編譯。

For count = 100 000, element size = 4 bytes:

std::vector:                7.5 seconds   
std::list:                 19.6 seconds                            
MyVector:                   3.2 seconds                              
MyVector using memmove:     2.1 seconds

For count = 200 000, element size = 4 bytes:
std::vector:                30.3 seconds                          
std::list:                  45.5 seconds                          
MyVector:                   13.1 seconds
MyVector using memmove:      8.7 seconds   

For count = 20 000, element size = 128 bytes:
std::vector:                5.36 seconds
std::list:                  1.37 seconds
MyVector:                   5.12 seconds
MyVector (memmove)          1.68 seconds

我知道這不是你會做的真實生活,這些是我為了表明緩存很重要而做的一些實驗,我偶然發現了std向量插入的工作方式。

另外我知道MyVector是一個不好的矢量實現。 我只是快速編寫它以測試我對插入的假設。 我只想討論insert()實現,而不是Vector類設計:)。

感謝您閱讀本文

事實證明,沒有特別的理由在std :: vector :: insert中調用rotate。

我將在此處粘貼insert()中使用的visual studio 2015的rotate實現:

template<class _RanIt> inline
    _RanIt _Rotate(_RanIt _First, _RanIt _Mid, _RanIt _Last,
        random_access_iterator_tag)
    {   // rotate [_First, _Last), random-access iterators
    _STD reverse(_First, _Mid);
    _STD reverse(_Mid, _Last);
    _STD reverse(_First, _Last);
    return (_First + (_Last - _Mid));
    }

// TEMPLATE FUNCTION reverse
template<class _BidIt> inline
    void _Reverse(_BidIt _First, _BidIt _Last, bidirectional_iterator_tag)
    {   // reverse elements in [_First, _Last), bidirectional iterators
    for (; _First != _Last && _First != --_Last; ++_First)
        _STD iter_swap(_First, _Last);
    }

更高速緩存友好的實現將提高此方法的速度(vector :: insert)。

我知道因為來自微軟STL的人都知道這個問題:)

https://twitter.com/StephanTLavavej/status/695013465342083072

暫無
暫無

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

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