我的new
宏有#define,要使用我自己的分配器,例如MYNEW(Type, Allocator)
,我将使用malloc
分配一些原始内存,然后使用放置new用于在原始内存上分配类型,例如
#define MYNEW(Type, Allocator) Allocator->Alloc<Type>(sizeof(Type));`
template<typename Type>
Type* Alloc(unsigned int size) // Allocator::Alloc<Type>
{
return (Type*)new(malloc(reportedSize)) Type;
}
但是,当Type
没有默认构造函数时,我遇到了问题。我尝试过的一个场景是做MYNEW_1(Type, Allocator, ConVar1)
之类的事情,其中会传递ConVar1,例如
#define MYNEW_1(Type, Allocator, ConVar1) Allocator->Alloc<Type>(sizeof(Type), ConVar1);`
template<typename Type, typename ConVarType>
Type* Alloc(unsigned int size, ConVarType Convar1) // Allocator::Alloc<Type>
{
return (Type*)new(malloc(reportedSize)) Type(Convar1);
}
这种方法的问题是,对于我的自定义Vector,我也使用MYNEW来分配内存。但是,对于我的Vector使用的一些Type
,没有默认构造函数,我无法分辨构造函数可能需要多少变量。
有没有人对如何解决这个问题有任何见解? (当然没有说使用std :: types而不是我自己的。我这样做是为了了解更多)。我不希望重载operator new
,因为我在那里有内存跟踪,因为我不希望内存跟踪两次(Alloc
有更多的内部跟踪,但我所展示的是简化示例)而宁愿使用malloc。
答案 0 :(得分:4)
看起来您不仅要做自己的自定义分配器,而且还不一定要尝试定义兼容STL的分配器。但是,我认为识别出所有的错误是有用的,STL分配器是为处理这种情况而设计的。 Allocation与construction分开:
请注意,[
allocator::construct
]不为元素分配空间,它应该已在p
处可用(请参阅成员allocate
以分配空间)。相当于[复制现有对象的[{1}}调用]。
一般来说,我相信你有两个选择:(1)重载new
来处理分配内存并让系统处理构造,或者(2)使你的分配器接口更像STL分配器接口。
“重载operator new
”通常用于表示两件事:(1)替换它,或(2)添加新版本的operator new
。当我最初回答时,我使用的是第一个含义(实际上应该称为“替换new
”或“覆盖operator new
”;但是考虑到这一点,我已经确定真正超载operator new
会满足您的要求。
我应该提一下,调用重载operator new
的语法是如此糟糕,以至于许多人仅仅出于这个原因就避免使用这种技术。您可以创建一个函数(例如operator delete
)并使用它,而不是重载delete
。
这种方法的价值在于您遵循将内存分配与对象构造分离的语言标准,并将其留给编译器来为您处理对象构造。您不必担心转发运算符,或者没有默认构造函数的类或任何这些问题。
重载deallocate
/ operator new
(当然,我依靠你来充实operator delete
和track
):
release
重载#include <new>
#include <cstdlib>
struct Allocator {
void track(void* p, const void* container) const;
void release(void* p, const void* container) const;
};
void* operator new (size_t size, const Allocator& alloc, const void* container)
{
void* allocated_memory = std::malloc(size);
if (!allocated_memory) {
throw std::bad_alloc();
}
alloc.track(allocated_memory, container);
return allocated_memory;
}
void operator delete(void* p, const Allocator& alloc, const void* container)
{
alloc.release(p, container);
std::free(p);
}
int main()
{
Allocator alloc;
int* i = new (alloc, NULL) int;
operator delete(i, alloc, NULL);
}
并使用函数operator new
:
deallocate
您应该考虑的一个案例是当#include <new>
#include <cstdlib>
struct Allocator {
void track(void* p, const void* container) const;
void release(void* p, const void* container) const;
};
void* operator new (size_t size, const Allocator& alloc, const void* container)
{
void* allocated_memory = std::malloc(size);
if (!allocated_memory) {
throw std::bad_alloc();
}
alloc.track(allocated_memory, container);
return allocated_memory;
}
template<typename T> void deallocate(T* p, const Allocator& alloc, const void* container)
{
p->~T();
alloc.release(p, container);
std::free(p);
}
int main()
{
Allocator alloc;
int* i = new (alloc, NULL) int;
deallocate(i, alloc, NULL);
}
成功但构建对象失败时该怎么做。也就是说,当有足够的内存时,还有一些其他原因导致无法创建对象。该系统实际上足够智能,可以调用权限new
(具有系统认为应具有的签名的delete
)来释放分配的内存;但只有当delete
有该签名时才有。您可能希望重载delete
和提供operator delete
函数,其中一个函数是根据另一个函数定义的:
deallocate
答案 1 :(得分:1)
这是我使用可变参数模板和宏的解决方案。
#include <cstdlib>
#include <new>
#include <iostream>
using namespace std;
#define MYNEW(Allocator, ...) (Allocator)->Alloc(__VA_ARGS__);
template<typename Type>
struct Allocator{
template<typename... Args>
Type* Alloc(Args... args){
cout<<"weird allocator"<<endl;
return new(malloc(sizeof(Type))) Type(args...);
}
};
struct test{
test(int a, bool b, const char* c){
cout<<"test constructor with a="<<a<<", b="<<b<<", c="<<c<<endl;
}
};
int main(){
Allocator<test> myallocator;
test* obj=MYNEW(&myallocator, 3, true, "hello");
}
就个人而言,我认为没有一个干净的解决方案(读取,不要求你在没有可变参数的情况下明确写出Allocator
将在你分配对象的地方做什么)东西。
您还可以查看将其他参数(其他指向内存的指针)传递给新的运算符重载(yes it is possible)。