【问题标题】:Prevent std::function in gcc from allocating memory or increase threshhold防止 gcc 中的 std::function 分配内存或增加阈值
【发布时间】:2016-07-29 20:50:28
【问题描述】:

有什么方法可以防止 gcc 中的std::function 为更大的函数对象动态分配内存?

我希望以下代码在没有动态分配的情况下工作:

#include <functional>
#include <iostream>

// replace operator new and delete to log allocations
void* operator new (std::size_t n) {
    std::cout << "Allocating " << n << " bytes" << std::endl;
    return malloc(n);
}
void operator delete(void* p) throw() {
    free(p);
}

  class TestPlate
  {
    private:
        int value;

    public:
        int getValue(){ return value; }
        void setValue(int newValue) { value = newValue; }

        int doStuff(const std::function<int()>& stuff) { return stuff(); }

  };

int main()
{
    TestPlate testor;
    testor.setValue(15);
    const std::function<int()>& func =  std::bind(&TestPlate::getValue, &testor);

    std::cout << testor.doStuff(func) << std::endl;
    testor.setValue(25);
    std::cout << testor.doStuff(func) << std::endl;
}

但是它分配了 24 个字节。据我所知,这是因为指向方法的指针需要 16 个字节,而指向类实例的指针需要另外 8 个字节。这似乎要么 A 大于函数对象可用的内部内存,要么 B 是一个普通的错误。

我想知道是否有任何方法可以在不更改 std::function 的签名或创建大量额外包装代码的情况下规避此类行为。

【问题讨论】:

  • 标准规定 鼓励实现避免为小的可调用对象使用动态分配的内存,例如,其中 f 是一个只包含一个对象的指针或引用的对象和一个成员函数指针。编译器尽其所能。如果它不符合您的需求,那么...
  • clang + libc++ 在您的示例中没有分配任何内存 (coliru.stacked-crooked.com/a/52505806440111db)

标签: c++ c++11 gcc memory-management std-function


【解决方案1】:

不幸的是,GCC 的 function 只为指向内部存储的成员函数的指针提供空间,因此您的绑定表达式的结果不适合。

不过,您可以使用 lambda 表达式:

std::function<int()> f = [&]{ return testor.getValue(); };

这仅需要包含对testor 的引用的闭包类型的空间(它是指向成员的指针大小的一半,以及绑定结果大小的三分之一),并且 GCC 定义了该闭包以便它可以存储在std::function

【讨论】:

  • @T.C.我确实这样做了——这就是我测试过的。但不是出于某种原因我在这里输入的内容。谢谢。
【解决方案2】:

查看 libstdc++(GCC 的默认 C++ 库)的异常皮肤爬行的 functional 标头,我发现实际上不可能通过其当前实现来避免堆分配。它似乎有一个特殊的管理器和调用程序成员,它是堆分配的,并且它是类工作所必需的。如果你真的想看源,here you go,但那里肯定有黑魔法和巫术。

标头中有一些功能暗示传入custom allocators 是计划好的,但目前似乎还没有实现。

同时,你可以试试Boost.function

【讨论】:

  • 如果__stored_locally 条件为真,它将避免堆分配。不幸的是,对于比指向成员函数的指针更大的任何东西,这都是错误的,因此不能在本地存储它和指向对象的指针。
猜你喜欢
  • 2012-10-29
  • 2018-01-23
  • 1970-01-01
  • 2017-12-15
  • 1970-01-01
  • 2011-02-26
  • 2011-11-03
  • 2016-12-18
  • 1970-01-01
相关资源
最近更新 更多