C ++ NEW和DELETE Monitor:重载NEW和DELETE

时间:2016-05-14 02:56:32

标签: c++ xcode stl overloading exc-bad-access

我正在用C ++编写一个自定义内存管理器来监控" new"和"删除"用法。

在我的代码中,我重载了new,new [],delete,delete []运算符,并使用STL映射将分配的内存的地址保存为键值,并存储分配为映射值的字节数。我还更新了byte_counter和number_of_allocations。

我一直收到错误"线程1:EXC_BAD_ACCESS(代码= 2,地址= 0x7fff5f3fffd8)" (我使用XCode作为我的IDE)将我带到这段代码:

template <class _Tp, class _Compare, class _Allocator>
template <class ..._Args>
typename __tree<_Tp, _Compare, _Allocator>::__node_holder
__tree<_Tp, _Compare, _Allocator>::__construct_node(_Args&& ...__args)
{
    __node_allocator& __na = __node_alloc();
    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
    __node_traits::construct(__na, _VSTD::addressof(__h->__value_), _VSTD::forward<_Args>(__args)...);
    __h.get_deleter().__value_constructed = true;
    return __h;
}

这是我的代码:

#include <iostream>
#include <map>
#include <cstdlib>

using namespace std;

/********************************************************************************/

void* operator new (size_t st);
void* operator new [](size_t st);
void operator delete(void* p);
void operator delete [](void* p);

/********************************************************************************/

class DynamicMemoryManager
{
private:
    static int number_of_allocations;
    static size_t total_bytes;
    static map<const void*, const size_t> mem_map;

public:
    DynamicMemoryManager();

    static DynamicMemoryManager* create();
    static void destroy();

    static void print();
    static void add(const void* p, const size_t size);
    static void remove(const void* p);
};

int DynamicMemoryManager::number_of_allocations = 0;
size_t DynamicMemoryManager::total_bytes = 0;
map<const void*, const size_t> DynamicMemoryManager::mem_map;

DynamicMemoryManager::DynamicMemoryManager() {
    number_of_allocations = 0;
    total_bytes = 0;
    mem_map.clear();
}

void DynamicMemoryManager::print() {
    cout << "number_of_allocations: " << number_of_allocations << endl;
    cout << "total_bytes: " << total_bytes << endl;
}

void DynamicMemoryManager::add(const void* p, const size_t size) {
    number_of_allocations++;
    total_bytes += size;
    mem_map.insert(pair<const void*, const size_t>(p, size));
}

void DynamicMemoryManager::remove(const void*p) {
    size_t sz = mem_map[p];
    number_of_allocations--;
    total_bytes -= sz;
    mem_map.erase(p);
}

/********************************************************************************/

int main()
{
    DynamicMemoryManager::print();

    int* i = new int(88);
    double* d = new double(8.8);
    string* s = new string("8888");
    char* c = new char('8');

    DynamicMemoryManager::print();

    delete i;
    delete d;
    delete s;
    delete c;

    return 0;
}

/********************************************************************************/

void* operator new (size_t st) {
    void* p = malloc(st);
    DynamicMemoryManager::add(p, st);

    return p;
}

void* operator new [](size_t st) {
    void* p = malloc(st);
    DynamicMemoryManager::add(p, st);

    return p;
}

void operator delete(void* p) {
    free(p);
    DynamicMemoryManager::remove(p);
}

void operator delete [](void* p) {
    free(p);
    DynamicMemoryManager::remove(p);
}

我不确定为什么我的代码会出现BAD_ACCESS错误。我应该如何设计我的代码,以便在每次使用NEW和DELETE时成功更新STL地图?请帮忙,谢谢!

编辑:我发现错误来自我的重载NEW运算符无限递归。我的教授暗示我们应该在这段代码中引用void example5()。我仍然不确定我的代码中缺少什么,以防止我的重载NEW再次出现:

#include <array>
#include <map>
#include <functional>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <regex>
#include <chrono>
#include <ctime>
#include <vector>
#include <memory>

using namespace std::chrono;
using namespace std;

array<string, 12> smonths =
{
    "january",
    "february",
    "march",
    "april",
    "may",
    "june",
    "july",
    "august",
    "september",
    "october",
    "november",
    "december"
};

vector<string> Parse(string text, string split)
{
    vector<string> words;
    sregex_token_iterator end;
    regex pattern(split);
    for (sregex_token_iterator pos(text.begin(), text.end(), pattern); pos != end; ++pos)
    {
        if ((*pos).length() > 0)
        {
            if ((static_cast<string>(*pos))[0] != 0x20)
                words.push_back(*pos);
        }
    }
    return words;
}

int getHash(string s)
{
    hash<string> hstring;
    return hstring(s);
}

struct KeyValue : pair<string, int>
{
    string key;
    int value;
    KeyValue(string s, int n) { first = s; second = n; }
    KeyValue(const KeyValue& kv) { first = kv.first; second = kv.second; }
    KeyValue(const KeyValue&& kv) { first = kv.first; second = kv.second; }
};

bool operator == (const KeyValue a, const KeyValue b)
{
    return  a.first.compare(b.first) == 0;
}

/*

If you think about how you usually allocate memory dynamically 
(using the 'new' operator), you could ask why the STL provides 
such a thing called allocator that does all the memory management 
of the container classes. The concept of allocators was originally 
introduced to provide an abstraction for different memory models 
to handle the problem of having different pointer types on certain 
16-bit operating systems (such as near, far, and so forth). 
However, this approach failed. Nowadays, allocators serve as an 
abstraction to translate the need to use memory into a raw call 
for memory.  Allocators simply separate the implementation of 
containers, which need to allocate memory dynamically, from the 
details of the underlying physical memory management. You can simply 
apply different memory models such as shared memory, garbage 
collections, and so forth to your containers without any difficulty 
because allocators provide a common interface.

*/

template <typename T>
class MallocAllocator
{
public:
    typedef T value_type;
    MallocAllocator() {}
    template <typename U> MallocAllocator(const MallocAllocator<U>& other) {}
    T* allocate(size_t count)
    {
        return (T*)malloc(count * sizeof(T));
    }
    void deallocate(T* object, size_t n)
    {
        void* ptr = reinterpret_cast<void*>(object);
        free(ptr);
    }
};

MallocAllocator<void*> memoryManager;

void* operator new(size_t size)
{
    //cout << "Allocating memory..." << endl;
    auto newObject = memoryManager.allocate(size);
    return newObject;
}

void operator delete(void* objectPtr) noexcept 
{
    void** ptr = reinterpret_cast<void**>(objectPtr);
    memoryManager.deallocate(ptr, 0);
    //free(objectPtr);
}

template <typename _Type = void>
struct Less
{   // functor for operator<
    constexpr bool operator()(const _Type& _Left, const _Type& _Right) const
    {   
        return (_Left < _Right);
    }
};

void example5()
{
    int* p = new int;
    system_clock::time_point tbegin = system_clock::now();
    map<string, int, Less<string>, MallocAllocator<int>> frequency;
    ifstream infile("Words.txt");
    while (!infile.eof())
    {
        string buffer;
        getline(infile, buffer);
        frequency[buffer] = 0;
    }
    infile.close();
    infile.open("Speech.txt");
    while (!infile.eof())
    {
        string buffer;
        getline(infile, buffer);
        vector<string> vs = Parse(buffer, "[a-zA-Z0-9]*");
        for (string s : vs)
        {
            int& number = frequency[s];
            ++number;
        }
    }
    ofstream outfile("Frequency.txt");
    for (auto p : frequency)
    {
        if (p.second)
        {
            outfile << p.first << "\t" << p.second << endl;
            cout << p.first << "\t" << p.second << endl;
        }
    }
    outfile.close();
    system_clock::time_point tend = system_clock::now();
    cout << "Duration: " << static_cast<double>((tend - tbegin).count()) / 10000000.0 << endl;
}

1 个答案:

答案 0 :(得分:0)

  

我应该如何设计我的代码,以便在每次使用NEW和DELETE时成功更新STL地图?

不容易。 std::map<Key,T,Compare,Allocator>的方法分配和释放动态内存, 存储和丢弃地图的元素。

它们使用Allocator的相应成员函数分配和释放动态内存。默认情况下 Allocator std::allocator<std::pair<const Key, T>> std::allocator通过调用来分配operator new operator delete 全局std::map并通过调用全局operator new解除分配(即 您要替换的受监控版本的操作符,用于插入和删除元素 您的std::map<Key,T,Compare,CustomAllocator>)。

因此,当你的CustomAllocator开始插入第一个元素时 在地图中,它会在插入操作中再次调用,从而开始另一次插入 操作,等等,直到你的内存耗尽和崩溃(如你所见)。

避免这种情况的唯一方法是将地图设为::operator new, 其中::operator delete是您自己编写的分配器,分配和释放 动态内存而不调用malloc/free/* RENDER THE FILES */ foreach ($files as $file) { ..... <td> <?php // FILENAME if(is_dir($dir.'/'.$file)) { echo '<div class="sfmfolder">'.$file.'</div><br />'; } else { echo '<div class="sfmfile">'.$file.'</div>'; } ?> </td> <td> <?php // RENAME if($_POST['renamefile']) { if(is_dir($dir.'/'.$file)){ rename($dir.'/'.$file, $dir.'/'.$_POST['rename']); } else { rename($dir.'/'.$file, $dir.'/'.$_POST['rename'].'.'.$FileExtension); } } ?> <form method="post" action=""> <input type="text" name="rename" /> <input type="submit" name="renamefile" value="go" /> </form> </td>

您可以尝试使用标准C库的malloc和。{ free

但我敦促你不要打扰。如果你认为你的记忆经理会 揭示关于堆的所有内容,你必须编写它的方式就足够了 告诉你它不会。它不知道它自己的堆使用情况,也不知道 处理堆栈的程序中链接的任何其他内容的堆使用情况 $dir.'/'.$file界面。要查看堆发生了什么,解决方案是Valgrind 对于OS X,请参阅Yosemite and Valgrind