से पहले मैं अपने पिटारे में std::max_align_t
था (जो अब <cstddef>
में रहती है) यह कोड लिखा गया था। अब मैं इसे इस प्रकार लिखूंगा:
static const std::size_t alignment = alignof(std::max_align_t);
जो मेरी प्रणाली पर वर्तमान कोड के बराबर है, लेकिन अब और अधिक पोर्टेबल है। यह संरेखण है जो new
और malloc
वापस लौटने की गारंटी है। और एक बार जब आपके पास यह "अधिकतम गठबंधन" बफर होता है, तो आप इसमें किसी एक प्रकार का सरणी डाल सकते हैं। लेकिन आप अलग-अलग प्रकार के लिए arena
का उपयोग नहीं कर सकते हैं (कम से कम अलग-अलग प्रकार के अलग-अलग संरेखण आवश्यकताओं वाले नहीं)। और इसी कारण से, शायद यह पर दूसरे size_t
पर टेम्पलेट के लिए सबसे अच्छा होगा, जो alignof(T)
के बराबर है। कि जिस तरह से आप एक ही arena
से गलती से भिन्न संरेखण आवश्यकताओं के साथ प्रकार के द्वारा प्रयोग किया जा रहा रोका जा सकता है:
arena<N, alignof(T)>& a_;
ही संरेखण आवश्यकताओं arena
से प्रत्येक आवंटन मानते हुए है, और बफर संभालने अधिकतम गठबंधन है, तो हर आवंटन बफर T
के लिए उपयुक्त रूप से गठबंधन किया जाएगा।
उदा। मेरे सिस्टम alignof(std::max_align_t) == 16
पर। इस संरेखण के साथ एक बफर के
alignof == 1
के साथ प्रकार हो सकते हैं।
alignof == 2
के साथ प्रकार।
alignof == 4
के साथ प्रकार।
alignof == 8
के साथ प्रकार।
alignof == 16
के साथ प्रकार।
कुछ वातावरण है कि "सुपर संरेखण" आवश्यकताओं प्रकार का समर्थन कर सकते हैं, एक अतिरिक्त सुरक्षा एहतियात जोड़ने के लिए होगा (short_alloc
भीतर कहते हैं):
static_assert(alignof(T) <= alignof(std::max_align_t), "");
आप सुपर पागल तुम भी जांच कर सकता है कर रहे हैं कि alignof(T)
2 की शक्ति है, हालांकि सी ++ मानक स्वयं गारंटी देता है कि यह हमेशा सत्य होगा ([basic.align]/p4)।
अद्यतन
मैं इस समस्या को करीब से देख लिया है और विश्वास है कि अगले alignment
करने का अनुरोध किया आवंटन आकार (के रूप में ओ पी सुझाव) गोलाई सबसे अच्छा समाधान है है। मैंने अपनी वेबसाइट पर ऐसा करने के लिए "short_alloc" अपडेट किया है।
template <std::size_t N>
char*
arena<N>::allocate(std::size_t n)
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
n = align_up(n);
if (buf_ + N - ptr_ >= n)
{
char* r = ptr_;
ptr_ += n;
return r;
}
return static_cast<char*>(::operator new(n));
}
विशेष स्थितियों में, जहां आप जानते हैं
है कि आप अधिकतम गठबंधन आवंटन की जरूरत नहीं है (उदाहरण के लिए
vector<unsigned char>
), एक बस
alignment
उचित रूप से ठीक कर सकते हैं के लिए
। और एक भी short_alloc::allocate
पास alignof(T)
arena::allocate
template <std::size_t N>
char*
arena<N>::allocate(std::size_t n, std::size_t requested_align)
{
assert(requested_align <= alignment);
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
n = align_up(n);
if (buf_ + N - ptr_ >= n)
{
char* r = ptr_;
ptr_ += n;
return r;
}
return static_cast<char*>(::operator new(n));
}
करने और assert(requested_align <= alignment)
यह आपको विश्वास है कि अगर आप alignment
नीचे समायोजित, आप इसे बहुत दूर नीचे समायोजित नहीं किया देना होगा हो सकता था।
फिर से अपडेट करें!
मैंने इस उत्कृष्ट प्रश्न के कारण इस आवंटन के description और code को अद्यतन किया है (मैंने इस कोड को वर्षों से उपेक्षित कर दिया है)।
पिछले अद्यतन में उल्लिखित संरेखण जांच अब संकलन-समय पर किया गया है (संकलन-समय त्रुटियां हमेशा रन-टाइम त्रुटियों से भी बेहतर होती हैं, यहां तक कि आवेषण भी)।
arena
और short_alloc
दोनों अब संरेखण पर टेम्पलेट किए गए हैं ताकि आप आसानी से संरेखण आवश्यकताओं को अनुकूलित कर सकें (और यदि आप बहुत कम अनुमान लगाते हैं तो यह संकलन समय पर पकड़ा जाता है)। यह टेम्पलेट पैरामीटर alignof(std::max_align_t)
पर डिफॉल्ट किया गया है।
arena::allocate
समारोह अब की तरह दिखता है:
template <std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign>
char*
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (buf_ + N - ptr_ >= aligned_n)
{
char* r = ptr_;
ptr_ += aligned_n;
return r;
}
return static_cast<char*>(::operator new(n));
}
उर्फ टेम्पलेट्स के लिए धन्यवाद, यह संभाजक पहले से कहीं ज्यादा उपयोग करने के लिए आसान है। उदाहरण के लिए:
// Create a vector<T> template with a small buffer of 200 bytes.
// Note for vector it is possible to reduce the alignment requirements
// down to alignof(T) because vector doesn't allocate anything but T's.
// And if we're wrong about that guess, it is a comple-time error, not
// a run time error.
template <class T, std::size_t BufSize = 200>
using SmallVector = std::vector<T, short_alloc<T, BufSize, alignof(T)>>;
// Create the stack-based arena from which to allocate
SmallVector<int>::allocator_type::arena_type a;
// Create the vector which uses that arena.
SmallVector<int> v{a};
यह जरूरी नहीं कि इस तरह के allocators में अंतिम शब्द है। लेकिन उम्मीद है कि यह एक ठोस नींव है जिस पर आप अपने कस्टम आवंटकों का निर्माण कर सकते हैं।
पेजिंग डॉक्टर [@ हावर्ड हिन्नेंट] (http://stackoverflow.com/users/576911/howard-hinnant) – sehe