在std :: allocator上漫游

Mac*_*ade 1 c++ std allocator

我最近有兴趣std::allocator,认为它可能解决我对C++代码的一些设计决定的问题.

现在我已经阅读了一些关于它的文档,观看了一些视频,比如Andrei Alexandrescu在2015年CppCon上的一个视频,我现在基本上明白我不应该使用它们,因为它们不是按照我认为分配器可能工作的方式工作的.

话虽如此,在实现这一点之前,我编写了一些测试代码,以了解自定义子类如何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;
}
Run Code Online (Sandbox Code Playgroud)

完整的代码TestAllocator在本问题的最后提供.

在这里,我只是用我的自定义分配器一些std::basic_string,并用std::vector.

有了std::basic_string,我可以看到我的分配器的实例实际上是创建的,但是没有调用任何方法......
所以看起来它根本就没用过.

但是std::vector,我自己的allocate方法实际上被调用了.

那么为什么这里有区别?

我尝试过不同的编译器和C++版本.看起来像旧的GCC版本,使用C++ 98,会调用allocate我的TestString类型,但不会调用C++ 11及更高版本的新版本.铿也不打电话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;
}
Run Code Online (Sandbox Code Playgroud)

Vit*_*meo 5

std::basic_string可以使用小缓冲区优化 (在字符串上下文中也称为SBO或SSO)来实现 - 这意味着它在内部存储一个小缓冲区,避免了对小字符串的分配.这很可能是您的分配器未被使用的原因.

尝试更改"hello"为更长的字符串(超过32个字符),它可能会调用allocate.

另请注意,C++ 11标准禁止std::string以COW (写时复制)方式实现 - 此问题中的更多信息:"C++ 11中COW std :: string实现的合法性"


标准禁止std::vector使用小缓冲区优化:在这个问题中可以找到更多信息:" std::vector可以使用小缓冲区优化吗?" .