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