2012-10-17 28 views
38

क्या कस्टम स्ट्रक्चर के std::vector को सिम निर्देशों के साथ आगे संसाधित करने के लिए गठबंधन स्मृति आवंटित करना संभव है? यदि Allocator के साथ करना संभव है, तो क्या किसी के पास ऐसा आवंटन होता है जिसे वह साझा कर सकता है?बनाना std :: vector गठबंधन स्मृति आवंटित

+1

पर प्रलेखन देखें क्या आपने यह देखने के लिए जांच की है कि मानक आवंटक पहले से ही आपके लिए क्या करता है या नहीं? – TemplateRex

+2

@rhalbersma: मुझे नहीं लगता कि यह करता है, यह संरेखण पैरामीटर नहीं लेता है। –

+0

मेरा मतलब यह नहीं है: क्या आपका एसटीएल कार्यान्वयन पहले से ही आपके लिए स्मृति संरेखित करता है? क्या आपने 'v.begin()' के मेमोरी पते की गणना की है और जांचें कि यह एक्स बाइट्स के एकाधिक में शुरू होता है या नहीं? भले ही आप संरेखण को स्पष्ट रूप से कॉन्फ़िगर नहीं कर सकते हैं, फिर भी std :: आवंटक पहले से ही आपकी सहायता कर सकता है। – TemplateRex

उत्तर

26

संपादित करें: मैंने जीएमएनएनजीजी द्वारा सुझाए गए अनुसार std::allocator की विरासत को हटा दिया और संरेखण पैरामीटर को संकलित समय की चीज़ बना दी।

मैंने हाल ही में कोड का यह टुकड़ा लिखा है। जितना मैं चाहूंगा उतना परीक्षण नहीं किया जाता है इसलिए त्रुटियों की रिपोर्ट करें और रिपोर्ट करें। :-)

enum class Alignment : size_t 
{ 
    Normal = sizeof(void*), 
    SSE = 16, 
    AVX = 32, 
}; 


namespace detail { 
    void* allocate_aligned_memory(size_t align, size_t size); 
    void deallocate_aligned_memory(void* ptr) noexcept; 
} 


template <typename T, Alignment Align = Alignment::AVX> 
class AlignedAllocator; 


template <Alignment Align> 
class AlignedAllocator<void, Align> 
{ 
public: 
    typedef void*    pointer; 
    typedef const void*  const_pointer; 
    typedef void    value_type; 

    template <class U> struct rebind { typedef AlignedAllocator<U, Align> other; }; 
}; 


template <typename T, Alignment Align> 
class AlignedAllocator 
{ 
public: 
    typedef T   value_type; 
    typedef T*  pointer; 
    typedef const T* const_pointer; 
    typedef T&  reference; 
    typedef const T& const_reference; 
    typedef size_t size_type; 
    typedef ptrdiff_t difference_type; 

    typedef std::true_type propagate_on_container_move_assignment; 

    template <class U> 
    struct rebind { typedef AlignedAllocator<U, Align> other; }; 

public: 
    AlignedAllocator() noexcept 
    {} 

    template <class U> 
    AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept 
    {} 

    size_type 
    max_size() const noexcept 
    { return (size_type(~0) - size_type(Align))/sizeof(T); } 

    pointer 
    address(reference x) const noexcept 
    { return std::addressof(x); } 

    const_pointer 
    address(const_reference x) const noexcept 
    { return std::addressof(x); } 

    pointer 
    allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0) 
    { 
     const size_type alignment = static_cast<size_type>(Align); 
     void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T)); 
     if (ptr == nullptr) { 
      throw std::bad_alloc(); 
     } 

     return reinterpret_cast<pointer>(ptr); 
    } 

    void 
    deallocate(pointer p, size_type) noexcept 
    { return detail::deallocate_aligned_memory(p); } 

    template <class U, class ...Args> 
    void 
    construct(U* p, Args&&... args) 
    { ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); } 

    void 
    destroy(pointer p) 
    { p->~T(); } 
}; 


template <typename T, Alignment Align> 
class AlignedAllocator<const T, Align> 
{ 
public: 
    typedef T   value_type; 
    typedef const T* pointer; 
    typedef const T* const_pointer; 
    typedef const T& reference; 
    typedef const T& const_reference; 
    typedef size_t size_type; 
    typedef ptrdiff_t difference_type; 

    typedef std::true_type propagate_on_container_move_assignment; 

    template <class U> 
    struct rebind { typedef AlignedAllocator<U, Align> other; }; 

public: 
    AlignedAllocator() noexcept 
    {} 

    template <class U> 
    AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept 
    {} 

    size_type 
    max_size() const noexcept 
    { return (size_type(~0) - size_type(Align))/sizeof(T); } 

    const_pointer 
    address(const_reference x) const noexcept 
    { return std::addressof(x); } 

    pointer 
    allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0) 
    { 
     const size_type alignment = static_cast<size_type>(Align); 
     void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T)); 
     if (ptr == nullptr) { 
      throw std::bad_alloc(); 
     } 

     return reinterpret_cast<pointer>(ptr); 
    } 

    void 
    deallocate(pointer p, size_type) noexcept 
    { return detail::deallocate_aligned_memory(p); } 

    template <class U, class ...Args> 
    void 
    construct(U* p, Args&&... args) 
    { ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); } 

    void 
    destroy(pointer p) 
    { p->~T(); } 
}; 

template <typename T, Alignment TAlign, typename U, Alignment UAlign> 
inline 
bool 
operator== (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept 
{ return TAlign == UAlign; } 

template <typename T, Alignment TAlign, typename U, Alignment UAlign> 
inline 
bool 
operator!= (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept 
{ return TAlign != UAlign; } 

वास्तविक आवंटन कॉल के लिए कार्यान्वयन केवल पॉज़िक्स है लेकिन आप आसानी से उस सीमा तक सीमित हो सकते हैं।

void* 
detail::allocate_aligned_memory(size_t align, size_t size) 
{ 
    assert(align >= sizeof(void*)); 
    assert(nail::is_power_of_two(align)); 

    if (size == 0) { 
     return nullptr; 
    } 

    void* ptr = nullptr; 
    int rc = posix_memalign(&ptr, align, size); 

    if (rc != 0) { 
     return nullptr; 
    } 

    return ptr; 
} 


void 
detail::deallocate_aligned_memory(void *ptr) noexcept 
{ 
    return free(ptr); 
} 

सी ++ 11, बीटीडब्ल्यू की आवश्यकता है।

+0

मुझे नहीं लगता कि आपको 'std :: अपवाद <>' 'std :: आवंटक <>' से प्राप्त करने की आवश्यकता है या नहीं। – GManNickG

+0

@GManNickG, शायद आप 'आवंटक' का मतलब था? :) – avakar

+0

@avakar: वाह, मैंने यह भी नहीं देखा कि मैंने लिखा है! – GManNickG

3
+1

हालांकि यह लिंक प्रश्न का उत्तर दे सकता है, लेकिन यहां उत्तर के आवश्यक हिस्सों को शामिल करना बेहतर है और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक किए गए पृष्ठ में परिवर्तन होने पर लिंक-केवल उत्तर अमान्य हो सकते हैं।- [समीक्षा से] (/ समीक्षा/कम गुणवत्ता वाली पोस्ट/18787539) –

15

आगामी संस्करण 1.56 में, बूस्ट पुस्तकालय: यदि आप गूगल पर इस सवाल डाल देता है तो आपके नमूना कोड के बहुत सारे मिल जाएगा, नीचे कुछ आशाजनक परिणाम है बूस्ट शामिल होंगे। साइन इन करें। अन्य मेमोरी संरेखण सहायकों में यह boost::alignment::aligned_allocator प्रदान करता है, जिसे std::allocator के लिए ड्रॉप-इन प्रतिस्थापन का उपयोग किया जा सकता है और आपको एक संरेखण निर्दिष्ट करने की अनुमति देता है। https://boostorg.github.io/align/

+0

यह जानना अच्छा है, लेकिन व्यक्तिगत रूप से मुझे अपनी परियोजनाओं में एकीकृत करने के लिए काफी दर्द होता है (वे पुस्तकालय जो केवल शीर्षलेख नहीं हैं)। –

+3

मैं मानता हूं कि बढ़ावा को एकीकृत करना दर्द का थोड़ा सा हो सकता है। हालांकि, 'Boost.Align' _is_ हेडर-केवल और केवल अन्य हेडर-केवल लाइब्रेरी AFAICS पर निर्भर करता है। – tklauser

+2

अब यह उपलब्ध है: http://www.boost.org/doc/libs/1_56_0/libs/core/doc/html/index.html – fireboot