Make_shared与自定义的新操作符

make_shared with custom new operator

本文关键字:操作符 自定义 shared Make      更新时间:2023-10-16

这可能是重复的,但我在任何地方都找不到解决方案。

我有这样的源代码:

struct Blob{
    //...    
    static void *operator new(size_t size_reported, size_t size) {
        return ::operator new(size);
    }
};

我这样使用它:

std::shared_ptr<Blob> blob;
// ...
size_t size = calcSize(); // it returns say 231
Blob *p = new(size) Blob();
blob.reset(p);

我能不能改变代码,让我可以使用std::make_sharedstd::allocate_shared,这样我就有了single allocation而不是two allocations ?


更新

我能够消除new并将代码简化为以下内容:

struct Blob{
    //...    
};
std::shared_ptr<Blob> blob;
// ...
size_t size = calcSize(); // it returns say 231
// allocate memory
void *addr = ::operator new(size);
// placement new
Blob *p = ::new(addr) Blob();
blob.reset(p);

它做完全相同的事情,但我认为现在更清楚我要做什么

我是这么想的

由于没有办法将大小传递给分配器,您可以通过global variableclass member来实现。

在这两种情况下,解决方案一点也不优雅,而且相当危险——当代码需要维护时,灾难随时可能发生。

如果allocate_sharedshared_ptr控制块放在缓冲区类之后,可能会发生另一个意想不到的问题。

在这种情况下,将有明确的缓冲区溢出,因为sizeof(buffer)将报告大小为1字节左右。

再次-代码正在工作,但将来肯定会有问题。


#include <stdio.h>
#include <string.h>
#include <memory>
// ============================
class buffer{
public:
    buffer(const char *s){
        strcpy(x, s);
    }
    char x[1];
};
// ============================
template <typename T>
struct buffer_allocator {
    using value_type = T;
    buffer_allocator() = default;
    template <class U>
    buffer_allocator(const buffer_allocator<U>&) {}
    T* allocate(size_t n) {
        void *p = operator new(n * sizeof(T));
        printf("Allocate   %p, (%zu)n", p, get_size());
        return (T*) p;
    }
    void deallocate(T* p, size_t n) {
        delete p;
        printf("Deallocate %p, (%zu)n", p, get_size());
    }
    size_t get_size(){
        return size;
    }
    void set_size(size_t size){
        this->size = size;
    }
private:
    size_t size = 0;
};
template <typename T, typename U>
inline bool operator == (const buffer_allocator<T>&, const buffer_allocator<U>&) {
  return true;
}
template <typename T, typename U>
inline bool operator != (const buffer_allocator<T>& a, const buffer_allocator<U>& b) {
  return !(a == b);
}
// ============================
int main(int argc, char *argv[]){
    buffer_allocator<buffer> ba;
    const char *s = "hello world!";
    ba.set_size( strlen(s) + 1 );
    auto b = std::allocate_shared<buffer>(ba, s);
    printf("Pointer    %pn", b.get());
    printf("%sn", b->x);
    printf("%zun", b.use_count());
    auto b1 = b;
    printf("%zun", b1.use_count());
    return 0;
}