2016-05-14 34 views
0

我在C++中編寫自定義內存管理器來監視「新建」和「刪除」用法。C++ NEW和DELETE監視器:重載NEW和DELETE

在我的代碼中,我重載了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()。我真不知道到底是什麼我缺少在我的代碼,以防止過載我來自新遞歸:

#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

你知道那'的std :: map'本身使用'new' /'delete'本身內部,爲管理內容的一部分的地圖,似乎調用你的重載操作符,對吧? –

回答

0

我應該如何設計我的代碼,以便它成功地更新STL地圖每位新刪除使用?

不容易。 std::map<Key,T,Compare,Allocator>的方法分配和釋放動態內存, 來存儲和丟棄地圖的元素。

它們使用Allocator的相應成員函數分配和釋放動態內存。默認情況下, Allocatorstd::allocator<std::pair<const Key, T>>std::allocator分配通過調用全球operator delete調用 全球operator new並釋放(也就是 運營商你與你的監控版本替換,其中插入和刪除元素的std::map的 )。

因此,當你operator new,例如,下到 地圖插入第一個元素,它就會再次插入操作,這將啓動另一個插入 操作調用,依此類推,直至耗盡內存和崩潰(如你所見)。

避免這個問題的唯一方法是使你的地圖的std::map<Key,T,Compare,CustomAllocator>, 其中CustomAllocator是你自己編寫的分配,其分配和重新分配 動態內存,而不調用::operator new::operator delete

您可能會嘗試使用標準C庫的mallocfree來做到這一點。

但我勸你不要打擾。如果你認爲你的內存管理器 會揭示堆的全部內容,那麼你將不得不編寫它的方式足以告訴你它不會。它不會知道任何關於它自己的堆使用情況的信息,也不知道關於通過 malloc/free接口處理堆的程序中鏈接的其他任何內容的堆使用情況。要看到堆發生了什麼,解決的辦法是Valgrind 對於OS X,請參閱Yosemite and Valgrind

+0

謝謝你的建議,邁克!這個程序是爲了完成一項家庭作業 - 我的教授暗示要在上面的代碼中看到void example5()(我只是將它添加到了我的問題中),但我不確定他所指的是exacxtly。我將嘗試編寫一個CustomAllocator並查看是否有效。 –

相關問題