make_shared with custom new operator

你。 提交于 2020-01-06 02:30:33

问题


This is probably a duplicate, but I cannot find the solution anywhere.

I have source code like this:

struct Blob{
    //...    

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

I use it like this:

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

Can I change the code somehow so I can use std::make_shared or std::allocate_shared so I have single allocation instead of two allocations?


Update

I was able to eliminate the new and simplify the code to the following:

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);

It does exactly the same thing, but I think now it is more clear what I'm trying to do.


回答1:


Here is what come up with.

Since there is no way to pass size to the allocator, you can do it via global variable or class member.

In both cases the solution is not elegant at all and is rather dangerous - disaster waiting to happen now or later when code needs to be maintained.

Another unexpected problem may happen if allocate_shared place the shared_ptr control block after the buffer class.

In such case there will be clear buffer overflow, because sizeof(buffer) will report size like 1 byte or so.

Once again - the code is working, but will have issues in the future for sure.


#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    %p\n", b.get());

    printf("%s\n", b->x);
    printf("%zu\n", b.use_count());
    auto b1 = b;
    printf("%zu\n", b1.use_count());

    return 0;
}


来源:https://stackoverflow.com/questions/31904439/make-shared-with-custom-new-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!