c++ - STL 中的额外分配和神奇的空间减少 - 使用右值引用

标签 c++ visual-c++ c++11

我用一个分配器替换了标准分配器,该分配器会“打电话通知”它消耗了多少内存。现在我正在检查我的一些代码,想知道为什么它分配然后释放这么多条目。

仅供引用,我并不是想预先优化我的代码或任何东西,我主要是好奇,除了我肯定需要知道我的总大小是否关闭,因为我需要确切地知道我的对象有多少用于 C# GC。

采用此示例函数:

void add_file(string filename, string source) {
    file_source_map.insert(std::pair<const string, string>(std::move(filename), std::move(source)));
}

它分配六次(48字节),然后释放四次(32字节)。由于该对是一个右值,并且我将字符串移入其中,因此映射肯定会分配一个新节点并将右值对移入其中,而不会触发任何更多分配,当然也不必取消分配任何分配。文件名和源参数也来自右值,应该移入,而不是复制。请注意:分配器也跟踪该字符串,它不是 std::string 而是 std::basic_string<char, std::char_traits<char>, Allocator<char>> .

仅供引用,我使用的是 MSVC。

这是我的分配器代码:

template<typename T>
class Allocator {
public : 
    //    typedefs

    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;

public : 
    //    convert an allocator<T> to allocator<U>

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

public : 
    Parser* parser;
    inline ~Allocator() {}
    inline Allocator(Allocator const& other) {
        parser = other.parser;
    }
    inline Allocator(Parser* ptr)
        : parser(ptr) {}
    template<typename U>
    inline Allocator(Allocator<U> const& other) {
        parser = other.parser;
    }

    //    address

    inline pointer address(reference r) { return &r; }
    inline const_pointer address(const_reference r) { return &r; }

    //    memory allocation

    inline pointer allocate(size_type cnt, 
        typename std::allocator<void>::const_pointer = 0) { 
            int newsize = cnt * sizeof (T);
            parser->size += newsize;
            std::cout << "Allocated " << newsize << "\n";
            return reinterpret_cast<pointer>(::operator new(newsize)); 
    }
    inline void deallocate(pointer p, size_type count) {
        size_type size = count * sizeof(T);
        ::operator delete(p); 
        parser->size -= size;
        std::cout << "Deallocated " << size << "\n";
    }

    //    size

    inline size_type max_size() const { 
        return std::numeric_limits<size_type>::max() / sizeof(T);
    }

    //    construction/destruction

    inline void construct(pointer p, const T& t) { new(p) T(t); }
    inline void destroy(pointer p) { p->~T(); }

    inline bool operator==(Allocator const& other) { return other.parser == parser; }
    inline bool operator!=(Allocator const& a) { return !operator==(a); }
};

当我通过包装函数从 C# 调用 add_file(上面发布)时,我可以在控制台上清楚地看到每个分配和释放以及它们的适当大小,这是 8 的 4 次分配,我知道的 80 之一来自映射,另外两次分配 8,然后四次释放 8,这对我来说,函数中有四个冗余字符串,因为它们都是右值,没有理由发生任何释放。

最佳答案

我在 VS 2010 中运行了您的代码,我相信您看到的分配只是 Visual Studio STL 调试工具,因为所有 8 字节分配都是从 _String_val 构造函数发出的:

  • 在发布版 (_ITERATOR_DEBUG_LEVEL == 0) 中,构造函数很简单
  • 在调试 (_ITERATOR_DEBUG_LEVEL != 0) 中,它通过分配器分配一个 _Container_proxy(大小恰好为 8)。

如果我在 Release模式下运行您的代码,则映射的节点分配会降至 72 字节,并且 8 字节分配和释放会消失:字符串似乎已正确移动。

关于c++ - STL 中的额外分配和神奇的空间减少 - 使用右值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4287230/

相关文章:

c++ - 将参数从可变参数函数转发到固定参数函数

c++ - 可以将右值移动到 shared_ptr 中吗

c++ - 在 C++ 中,结构是如何在内存中布局的?

c - 使用 cmake 链接 DX10

C++11 对模板参数类型的 vector 使用迭代器

C++11 最佳参数传递

c++ - 为什么我应该使用 CString 的 GetBuffer 成员而不是 SetAt?

c++ - 使用指针初始化多维数组

c++ - 类数组正在破坏数据

c++ - decltype 在不生成代码的模板方法上抛出错误