为什么std :: string分配两次?

时间:2014-02-24 05:09:17

标签: c++ c++11

我为std::stringstd::vector编写了一个自定义分配器,如下所示:

#include <cstdint>
#include <iterator>
#include <iostream>

template <typename T>
struct PSAllocator
{
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;

    template<typename U>
    struct rebind {typedef PSAllocator<U> other;};

    PSAllocator() throw() {};
    PSAllocator(const PSAllocator& other) throw() {};

    template<typename U>
    PSAllocator(const PSAllocator<U>& other) throw() {};

    template<typename U>
    PSAllocator& operator = (const PSAllocator<U>& other) { return *this; }
    PSAllocator<T>& operator = (const PSAllocator& other) { return *this; }
    ~PSAllocator() {}


    pointer allocate(size_type n, const void* hint = 0)
    {
        std::int32_t* data_ptr = reinterpret_cast<std::int32_t*>(::operator new(n * sizeof(value_type)));
        std::cout<<"Allocated: "<<&data_ptr[0]<<" of size: "<<n<<"\n";
        return reinterpret_cast<pointer>(&data_ptr[0]);
    }

    void deallocate(T* ptr, size_type n)
    {
        std::int32_t* data_ptr = reinterpret_cast<std::int32_t*>(ptr);
        std::cout<<"De-Allocated: "<<&data_ptr[0]<<" of size: "<<n<<"\n";
        ::operator delete(reinterpret_cast<T*>(&data_ptr[0]));
    }
};

然后我运行了以下测试用例:

int main()
{
    typedef std::basic_string<char, std::char_traits<char>, PSAllocator<char>> cstring;

    cstring* str = new cstring();
    str->resize(1);
    delete str;

    std::cout<<"\n\n\n\n";

    typedef std::vector<char, PSAllocator<char>> cvector;

    cvector* cv = new cvector();
    cv->resize(1);
    delete cv;
}

出于任何奇怪的原因,它继续打印:

Allocated: 0x3560a0 of size: 25
Allocated: 0x3560d0 of size: 26
De-Allocated: 0x3560a0 of size: 25
De-Allocated: 0x3560d0 of size: 26




Allocated: 0x351890 of size: 1
De-Allocated: 0x351890 of size: 1

那么为什么它为std::string和更多字节分配两次呢?

我在Windows 8上使用g ++ 4.8.1 x64 sjlj:http://sourceforge.net/projects/mingwbuilds/

1 个答案:

答案 0 :(得分:3)

我无法重现双重分配,因为显然我的libstdc ++根本没有为空字符串分配任何东西。然而,调整大小确实分配了26个字节,gdb帮助我识别how they are composed

size_type __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
                   (     1     + 1) *     1          +     24

因此,内存主要用于此_Rep表示,而后者又包含以下数据成员:

size_type    _M_length;   // 8 bytes
size_type    _M_capacity; // 8 bytes
_Atomic_word _M_refcount; // 4 bytes

我猜最后四个字节只是为了对齐,但我可能错过了一些数据元素。

我想在堆上分配这个_Rep结构的主要原因是它可以在字符串实例之间共享,也许还可以避免空字符串,因为缺少第一次分配我的系统建议。

要了解您的实现未使用此空字符串优化的原因,请查看the default constructor。它的实现似乎取决于_GLIBCXX_FULLY_DYNAMIC_STRING的值,它在您的设置中显然不为零。我不建议直接更改该设置,因为它以下划线开头,因此被视为私有。但是您可能会发现一些公共设置会影响此值。