C++ 处理自定义分配器中没有默认构造函数的问题
我有一个#define to myC++ 处理自定义分配器中没有默认构造函数的问题,c++,design-patterns,memory,memory-management,constructor,C++,Design Patterns,Memory,Memory Management,Constructor,我有一个#define to mynew宏,使用我自己的分配器,例如MYNEW(Type,allocator)我将使用malloc分配一些原始内存,然后使用placement new在原始内存上分配类型,例如 #define MYNEW(Type, Allocator) Allocator->Alloc<Type>(sizeof(Type));` template<typename Type> Type* Alloc(unsigned int size) // Al
new
宏,使用我自己的分配器,例如MYNEW(Type,allocator)
我将使用malloc
分配一些原始内存,然后使用placement 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;
}
这种方法的问题是,对于我的自定义向量,我还使用MYNEW来分配内存。但是,对于一些用于我的向量的类型
,没有默认构造函数,我无法告诉构造函数可能需要多少变量
有人知道如何解决这个问题吗?(当然不用说使用std::types而不是我自己的。我这样做是为了了解更多)。我不希望只重载
运算符new
,因为我在其中有内存跟踪,因为我不希望内存跟踪两次(对Alloc
有更多的内部跟踪,但我展示的是简化的示例)而且更愿意使用malloc。看起来您不仅在做自己的自定义分配器,而且也不一定要定义一个与STL兼容的分配器。然而,我认为认识到STL分配器设计用于处理所有故障是有用的。独立于:
请注意,[allocator::construct
]没有为元素分配空间,它应该已经在p
中可用(请参见成员分配以分配空间)
它相当于[调用placementnew
复制现有对象]
一般来说,我认为您有两种选择:(1)重载运算符new
来处理内存分配并让系统处理构造,或者(2)使您的分配器接口更像STL分配器接口
“重载运算符new
”通常用于表示两件事:(1)替换它,或(2)添加新版本的new
。当我最初回答时,我使用的是第一种含义(实际上应该称为“替换新操作员
”或“覆盖新操作员
”;但是考虑到这一点,我确定真正的重载操作符new
将满足您的要求
我应该提到的是,调用重载的操作符delete
的语法非常糟糕,以至于许多人仅仅因为这个原因就避免使用这种技术。您可以创建一个函数(例如,deallocate
)并使用它,而不是重载delete
这种方法的价值在于,您遵循将内存分配与对象构造分离的语言标准,并让编译器为您处理对象构造。您不必担心转发运算符、没有默认构造函数的类或任何这些问题
重载operator new
/operator delete
(当然,我依靠你来充实跟踪和发布):
一个你应该考虑的问题是,当<代码>新< /代码>成功时,但是构造对象失败了。也就是说,当有足够的内存时,但由于其他原因无法创建对象。系统实际上足够聪明,可以调用正确的
delete
(好的,delete
,它具有系统认为应该具有的签名)来释放分配的内存;但仅当存在带有该签名的删除
时。您可能希望重载运算符delete
并提供解除分配
功能,其中一个功能根据另一个定义:
void operator delete(void* p, const Allocator& alloc, const void* container)
{
alloc.release(p, container);
std::free(p);
}
template<typename T> void deallocate(T* p, const Allocator& alloc, const void* container)
{
p->~T();
operator delete(p, alloc, container);
}
void运算符删除(void*p、常量分配器和alloc、常量void*容器)
{
分配释放(p,容器);
std::游离(p);
}
模板无效解除分配(T*p、常量分配器和alloc、常量无效*容器)
{
p->~T();
运算符删除(p、alloc、container);
}
这是我使用可变模板和宏的解决方案
#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");
}
#包括
#包括
#包括
使用名称空间std;
#定义MYNEW(分配器…)(分配器)->Alloc(\uu VA\u ARGS\uuu);
模板
结构分配器{
模板
类型*Alloc(Args…Args){
coutVariadic模板可能是一种解决方案,当然,你不需要证明你的方法是正确的,特别是如果你只是在学习;但是出于好奇,你愿意评论一下为什么你希望避免定义默认构造函数吗?@thb:我使用的一些类没有默认构造函数,只有没有默认构造函数的构造函数参数。什么是分配器
?看起来像是一个有Alloc
方法的结构,但是Alloc
这里有一个免费函数。我缺少什么吗?@Paranaix:我很想知道变量模板如何解决这个问题。我以前读过关于它们的文章,我认为我的编译器没有完全支持但是,我确信这个问题在使用变量模板之前就已经存在了,所以我认为有另一种方法可以解决这个问题。我确实尝试在同一个函数中同时使用这两种方法。也许这只是幼稚,但我不认为我自己的分配方法将分配和构造分开的目的,我的MYNEW宏将始终是分配/构造的接口。正如我所提到的,我不想重载运算符new。根据我提供的代码,您能否展示我如何“使您的分配器接口更像STL分配器接口”@chadb:这既是一个你的分配器做什么的问题,也是一个如何使用它的问题(你的向量类如何使用它)。本质上,你的向量类必须始终(1)构造一个对象,然后(2)将构造的对象传递给分配器::construct
,以将其副本放入相关内存中
#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);
}
void operator delete(void* p, const Allocator& alloc, const void* container)
{
alloc.release(p, container);
std::free(p);
}
template<typename T> void deallocate(T* p, const Allocator& alloc, const void* container)
{
p->~T();
operator delete(p, alloc, container);
}
#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");
}