我最近對std::allocator
有一些興趣,認爲它可能解決我在C++代碼上做出的一些設計決策時遇到的問題。std :: allocator上的Rambling
現在我已閱讀了一些關於它的文檔,觀看了一些視頻,如Andrei Alexandrescu's one at CppCon 2015,我現在基本上明白我不應該使用它們,因爲它們不是按照我認爲分配器可以工作的方式工作。
這就是說,在實現這個之前,我寫了一些測試代碼來了解std::allocator
的自定義子類是如何工作的。
顯然,沒有按預期工作...:)
所以,問題不在於如何分配器應在C++中使用,但我只是好奇,確切的知道爲什麼我的測試代碼(提供下面)不起作用。
不是因爲我想使用自定義分配器。只是好奇,看到確切的原因...
typedef std::basic_string< char, std::char_traits<char>, TestAllocator<char> > TestString;
int main(void)
{
TestString s1("hello");
TestString s2(s1);
s1 += ", world";
std::vector< int, TestAllocator<int> > v;
v.push_back(42);
return 0;
}
在這個問題的最後提供了TestAllocator
的完整代碼。
在這裏,我只是使用我的自定義分配器與一些std::basic_string
和std::vector
。
隨着std::basic_string
,我可以看到我的分配器的實例被實際創建,但沒有一種方法被稱爲...
所以它只是看起來像它根本不使用。
但與std::vector
,我自己的allocate
方法實際上被調用。
那麼爲什麼這裏有區別?
我嘗試過使用不同的編譯器和C++版本。 看起來像舊的GCC版本,使用C++ 98,在我的TestString
類型上調用allocate
,但使用C++ 11和更高版本的新版本不能。 Clang也不會撥打allocate
。
所以只是好奇看到有關這些不同行爲的解釋。
分配器代碼: - 這意味着它在內部存儲一個小緩衝器
template< typename _T_ >
struct TestAllocator
{
public:
typedef _T_ value_type;
typedef _T_ * pointer;
typedef const _T_ * const_pointer;
typedef _T_ & reference;
typedef const _T_ & const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type is_always_equal;
template< class _U_ >
struct rebind
{
typedef TestAllocator<_U_> other;
};
TestAllocator(void) noexcept
{
std::cout << "CTOR" << std::endl;
}
TestAllocator(const TestAllocator & other) noexcept
{
(void)other;
std::cout << "CCTOR" << std::endl;
}
template< class _U_ >
TestAllocator(const TestAllocator<_U_> & other) noexcept
{
(void)other;
std::cout << "CCTOR" << std::endl;
}
~TestAllocator(void)
{
std::cout << "DTOR" << std::endl;
}
pointer address(reference x) const noexcept
{
return std::addressof(x);
}
pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0)
{
pointer p;
(void)hint;
std::cout << "allocate" << std::endl;
p = new _T_[ n ]();
if(p == nullptr)
{
throw std::bad_alloc() ;
}
return p;
}
void deallocate(_T_ * p, std::size_t n)
{
(void)n;
std::cout << "deallocate" << std::endl;
delete[] p;
}
const_pointer address(const_reference x) const noexcept
{
return std::addressof(x);
}
size_type max_size() const noexcept
{
return size_type(~0)/sizeof(_T_);
}
void construct(pointer p, const_reference val)
{
(void)p;
(void)val;
std::cout << "construct" << std::endl;
}
void destroy(pointer p)
{
(void)p;
std::cout << "destroy" << std::endl;
}
};
template< class _T1_, class _T2_ >
bool operator ==(const TestAllocator<_T1_> & lhs, const TestAllocator<_T2_> & rhs) noexcept
{
(void)lhs;
(void)rhs;
return true;
}
template< class _T1_, class _T2_ >
bool operator !=(const TestAllocator<_T1_> & lhs, const TestAllocator<_T2_> & rhs) noexcept
{
(void)lhs;
(void)rhs;
return false;
}
絕對真棒和正確!我沒有期待這麼快速的回答,但非常感謝。 :) SBO是否被C++標準明確允許,還是僅僅是編譯器所做的事情?如果允許,在哪個部分?試圖在我的C++ 11副本中進行搜索,但沒有運氣... – Macmade
@Macmade:**我對這個**不完全確定,但是我認爲**允許SBO,但不是必需的。因此,你不太可能會發現*「'std :: string'必須在標準中使用SBO」*來實現 - 我認爲這只是一個「明顯的」優化,可以在符合標準的同時實現。 –
對性能完全有意義,但也可能打破預期的行爲...奇怪我無法在標準中找到明確的內容。 – Macmade