问题
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