【问题标题】:make_shared with custom new operatormake_shared 与自定义新运算符
【发布时间】:2015-08-10 03:40:37
【问题描述】:

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

我有这样的源代码:

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

它做的事情完全一样,但我认为现在更清楚我要做什么了。

【问题讨论】:

  • 是的,把它改成std::shared_ptr&lt;Blob&gt; blob = std::make_shared&lt;Blob&gt;();,你会得到一个单一的分配。
  • 但这是“自定义”(重载)新运算符? Blob *p = new(size) Blob();
  • 你的重载运算符只用于new Blob,不能用于其他任何地方。重载operator new 通常是一个非常无用的功能,因为它没有与标准库的任何部分集成。我什至可以将其称为语言的错误特征,甚至提供此功能。看来我们现在已经了解到自定义内存分配的方法是通过库(即通过分配器)。
  • 那么,这是否意味着如果 Nick 想要确保使用重载的 new 时,应该在此处编写和使用自定义分配器?
  • @AaronMcDaid:不,这意味着任何人都不应该重载operator new,如果您想要自定义分配语义,请编写自定义分配器并将其用于所有内容。

标签: c++ c++11 new-operator shared-ptr


【解决方案1】:

这是想出的。

由于无法将大小传递给分配器,您可以通过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    %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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 2019-01-04
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多