gpt4 book ai didi

c++ - 漫谈 std::allocator

转载 作者:行者123 更新时间:2023-11-30 01:08:27 28 4
gpt4 key购买 nike

我最近对 ​​std::allocator 产生了一些兴趣,认为它可能会解决我在 C++ 代码的一些设计决策中遇到的问题。

现在我已经阅读了一些关于它的文档,观看了一些视频,例如 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_stringstd::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;
}

最佳答案

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

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

另请注意,C++11 标准禁止以 COW (写时复制) 方式实现 std::string - 更多信息请参见问题:"Legality of COW std::string implementation in C++11"


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

关于c++ - 漫谈 std::allocator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42705841/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com