【问题标题】:Is it possible to force `std::make_shared` to use a class's new operator?是否可以强制 `std::make_shared` 使用类的 new 运算符?
【发布时间】:2016-06-09 19:24:49
【问题描述】:

是否可以强制std::make_shared 使用类的新运算符?这与另一个SO question 有关。根据那个问题,std::make_shared 使用自定义分配器:

来自标准(§20.7.2.2.6 shared_ptr 创建):

效果:分配适合类型 T 对象的内存,并通过放置 new 表达式在该内存中构造一个对象 ::new (pv) T(std::forward(args)...)。

因此,我认为我可以使用自定义放置 new 运算符,但这似乎是错误的

// std::cout
#include <iostream>

// std::make_shared
#include <memory>

// Track what we're making
struct Foo {
    Foo() {
        std::cout << "Foo constructor" << std::endl;
    }
    Foo(Foo const & foo) {
        std::cout << "Foo copy constructor" << std::endl;
    }
    Foo(Foo && foo) {
        std::cout << "Foo move constructor" << std::endl;
    }
    Foo & operator = (Foo const & foo) {
        std::cout << "Foo copy assignment" << std::endl;
        return *this;
    }
    Foo & operator = (Foo && foo) {
        std::cout << "Foo move assignment" << std::endl;
        return *this;
    }
    void * operator new(std::size_t size) throw(std::bad_alloc) {
        std::cout << "Foo new" << std::endl;
        return ::operator new(size);
    }
    void * operator new(std::size_t size, void * p) throw() {
        std::cout << "Foo placement new" << std::endl;
        return ::operator new(size,p);
    }
    void* operator new (std::size_t size, std::nothrow_t const & nothrow_value) 
        throw()
    {
        std::cout << "Foo nonthrowing new" << std::endl;
        return ::operator new(size,nothrow_value);

    }
    void operator delete(void * p, std::size_t size) {
        std::cout << "Foo delete" << std::endl;
        ::operator delete(p);
    }
    ~Foo() {
        std::cout << "Foo destructor" << std::endl;
    }
};

int main() {
    std::cout << "---Creating foo" << std::endl;
    auto foo = std::make_shared <Foo> ();
    std::cout << "---Creating foo2" << std::endl;
    auto foo2 = std::shared_ptr <Foo> (new Foo());
    std::cout << "---Creating foo3" << std::endl;
    auto foo3 = std::allocate_shared <Foo> (std::allocator <Foo>());
    std::cout << "---fin" << std::endl;
}

给了

---Creating foo
Foo constructor
---Creating foo2
Foo new
Foo constructor
---Creating foo3
Foo constructor
---fin
Foo destructor
Foo destructor
Foo delete
Foo destructor

还有一个尝试强制分配器通过调用std::allocate_shared 来调用自定义新运算符。无论如何,有没有办法让std::make_shared 调用自定义的新运算符而不定义全新的分配器?

【问题讨论】:

  • Don't custom new(控制你自己的分配)和make_shared(不为你自己的类型进行第二次分配)有一些相反的目标吗?
  • 请注意,make_shared 会为 counting block 分配一次而不是两次。
  • 您引用的标准文本明确表示它使用::new,即全局而​​不是您的自定义。

标签: c++ c++11 c++14


【解决方案1】:

不,这是不可能的(make_shared)。

由于类T 的自定义分配器通常会被编写和优化(例如使用池)以期望分配大小为T,而make_shared 将分配更多内存除此之外,我想它不被认为是支持的重要功能。

此外,该标准为您希望使用自定义分配器的情况提供了allocate_shared

【讨论】:

    【解决方案2】:

    有点。

    您要做的是创建一个包含对齐存储的结构,其中包含一个自定义销毁器,用于清理对象和一个布尔值,说明您是否应该这样做。

    然后放置新的对齐存储。

    现在使用别名共享 ptr 构造函数将指向对齐存储的指针作为不同类型返回。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      • 2013-08-24
      • 1970-01-01
      • 2014-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多