私は最近、std::allocator
に興味を持ち、C++コードに関する設計上の問題を解決するかもしれないと考えました。std :: allocatorに乗って
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++バージョンを試しました。 C++ 98の古いGCCバージョンのように見えますが、私の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