继承自std :: function(尽管有现有的建议)

时间:2017-08-23 16:13:04

标签: function c++11 std rtti

我已经读过为什么继承std :: function是个坏主意的原因。我没有虚拟析构函数:我的程序中只有一个地方需要删除子类,我确切知道它在哪里,所以我很乐意进行手动删除。

如果我可以访问target(),我根本不需要这样做 - 我需要“包装”函数的地址,以便我可以在容器中再次找到它。我正在使用Arduino IDE 1.8.3(c ++ 11标准)并针对NodeMCU,Wemos D1,Sonoff等......硬件并不足以说明内存非常有限。因此stdlib是一个“削减”版本。例如,编译器标志不指定RTTI,当然,只有在存在RTTI时才编译target()等。我没有攻击,我甚至无法编译,因为可用的可执行文件对于可用的RAM来说太大了......

问题是我不需要花哨的typeinfo,只需要目标可调用的物理地址。

我的想法是从std :: function继承(对于应用程序中使用的唯一函数签名function<void()>),覆盖构造函数,捕获目标的地址并提供函数(不称为target( )以免混淆)在适当的时候检索它 - “getFn()”也许......这就是我已经用我自己的“任务”类做的事情,它工作正常。我需要为std扩展它:: function但除非能访问“目标”地址,否则我无法看到它是如何做到的!

最后,排除任何有助于回复的尝试,例如:将“句柄”返回到首先创建此函数的用户例程,然后让它们再次使用句柄来查找容器条目...我绝对不希望这样做。我已经为自己制作了一根杆,因为我的API必须避免接收任何手柄,然后使用它们回到原件。这不能改变,所以我不是在寻找替代方案,因此缺乏更精确的实施细节。

我只是要求从std :: function继承的建议。

总而言之,我想我的问题是:是否有任何其他原因导致为什么这可能不起作用,因为我我可以处理我已经存在的问题读一下?

这就是我的想法:

 class XFunction: public function<void()> {
  public:
    uint32_t  fn;
    XFunction(void (&_fn)() ): function<void()>(_fn) {
      Serial.printf("CTOR %08x fn=%08x\n", this,_fn);
      fn=reinterpret_cast<uint32_t>(&_fn);
   }
   uint32_t getFn(){
    return fn;
   }
};

1 个答案:

答案 0 :(得分:3)

  

捕获目标地址

立即无效的地址。或者至少可能是无效的。请记住:std::function存储包装函数的副本;它没有通过引用存储它。因此,如果您存储指向所提供的可调用T的指针,function将从此T复制并在内部存储该副本。所以你的指针不会指向内部对象。

哦,当然,如果T是一个实际的函数指针,你可以存储函数指针,它总是有效的(除了DLL / SOs)。但是如果T是一个仿函数,那么你存储的指针可能是一个堆栈对象或其他形式的&#34;最终会被破坏&#34;事情。它的生命周期不受std::function控制。

更不用说std::function也适用于成员指针,无法转换为通用void*。实际上,函数指针是否可以转换为void*并且返回是实现定义的。

所以不,你想要的一般是不合理的。如果你不想接受仿函数和成员指针,你就不会使用std::function;你只是带着一个裸体函数指针。如果您想为function分配某种唯一标识符,则必须采用不同的方式。

继承std::function不是你的问题。

  

事情是(并且听起来可能很愚蠢)但我并不十分关心它指向的内容 - 除了知道它之外,我永远不会去取消它或者对它进行调用或做任何事情。价值所以我可以再次找到它

但是你仍然需要它唯一,对吗?考虑一下:

XFunction some_func()
{
  int x = ...;
  return XFunction([x]{...});
}

lambda临时的位置很可能是堆栈中的东西。这意味着该函数的两次独立调用很可能将使用相同的堆栈地址作为lambda临时值。因此,尽管x可能具有不同的值,但您的系统会将这些单独的XFunction类视为相同的实例。

  

我尝试做的事情的本质是:1)创建函数对象说F1,将其传递给我将其存储在容器中的进程... 2)然后我想在中查找该项目容器仅使用F1(或其属性)。

一般情况下,您无法对可调用对象执行此操作。通常,函数对象没有任何类型的可比性,相等性或可确定的唯一身份的概念。特定的函数对象有一个地址,是的。但是,如果您(或用户)复制该仿函数,您可能希望他们“比较”#34;相等或产生相同的&#34;哈希&#34;,是吗?

好吧,仿函数不会这样做。虽然特定的仿函数可以提供平等或身份,但这些并不是仿函数的一般属性。如果没有这样的属性,就无法将它们转换为可测试的整数值。

鉴于你的设计,你想要的东西是行不通的。您有两种选择:

  1. 限制自己使用指针。

  2. 限制自己使用参考。也就是说,你根本不使用std::function。而是将类型擦除的指针存储到要调用的函数指针/仿函数/成员指针。你没有拥有这个物品,你不能复制它,虚无...。

    这意味着身份不是基于概念上的相等,而是基于相同的对象。因此,如果有人向您注册了lambda,然后通过副本将其返回给其他人,则视为与注册函数相等。

    这也意味着用户必须管理注册到此系统的任何功能对象的内存和生命周期。这意味着std::bind/mem_fn - 风格的东西永远不会在这样的系统中工作,因为这些类型需要接收器长期存储它们,而接收器只存储指针。

  3. 这是您唯一的选择。