Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 处理自定义分配器中没有默认构造函数的问题_C++_Design Patterns_Memory_Memory Management_Constructor - Fatal编程技术网

C++ 处理自定义分配器中没有默认构造函数的问题

C++ 处理自定义分配器中没有默认构造函数的问题,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

我有一个#define to my
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
中可用(请参见成员
分配
以分配空间)

它相当于[调用placement
new
复制现有对象]

一般来说,我认为您有两种选择:(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");
}