【问题标题】:Can a std::function's target callable legally destroy the std::function during execution?std::function 的可调用目标可以在执行期间合法地破坏 std::function 吗?
【发布时间】:2020-07-17 13:02:44
【问题描述】:

在另一个问题下的cmets中,有人说一个常见的错误是:

在调用 std::function 时调用它会导致销毁持有它的对象

虽然在健壮的代码中显然可以避免这样做的“危险”事情,但它真的是错误的吗?我在标准中找不到任何可以确保:

  • std::function 不得被其目标可调用对象销毁
  • std::function 的生命周期不得在其目标可调用对象执行期间结束
  • 函子的生命周期通常不能在其执行期间结束

据我所知,执行以下操作是合法且定义明确的(尽管品味不佳):

struct Foo
{
   void baz()
   {
      delete this;
      // Just don't use any members after this point
   }
};

int main()
{
   Foo* foo = new Foo();
   foo->baz();
}

这表明,在没有任何压倒一切的限制(我无法找到)的情况下,以下内容也将是技术上明确定义的:

#include <functional>

struct Bar
{
   std::function<void()> func;
};

int main()
{
   Bar* bar = new Bar();
   bar->func = [&]() { delete bar; };
   bar->func();
}

不是这样吗?如果不是,哪个措辞禁止?

(对于奖励积分,如果这与以前的标准相比有所改变,那将会很有趣。)

【问题讨论】:

  • @StoryTeller-UnslanderMonica 我不知道;标准says nothing about any "internal state object" 或其他任何东西;只有目标被调用。而已。如果一个实现选择做其他事情,那肯定是该实现冒昧,而不是似乎遵守规则的功能用户!因此,我认为本案不属于“措辞中未指明,故为UB”的范畴;我认为,在最好的情况下,实现会施加额外的要求/约束​​。
  • 我已经看到对象有if (self_destruct) delete this;,这似乎是一样的。似乎也很差劲,但我希望合法,因为我项目的代码库中有很多。
  • 可能属于“实现定义”的行为。如果标准中没有任何内容说明您可以或不能在函数对象执行时销毁它,那么听起来它可以解释要走哪条路。
  • @1201ProgramAlarm 如果是这样,那将是 UB(根据我的回忆,实现定义必须由标准明确规定)。但是,如上所述,我不相信这属于这一类。这就像说使用bool 是UB,因为标准没有告诉我们在吃意大利面时是否可以这样做。如果作为程序员,您满足函数调用的所有先决条件,那么您应该能够期望得到明确定义的结果。而且,根据我对链接段落的阅读,这就是这个假设的糟糕程序员所做的一切。

标签: c++ c++17 language-lawyer


【解决方案1】:

[res.on.objects]/2:

如果一个标准库类型的对象被访问,并且开始 对象的生命周期不会在访问之前发生,或者 访问不会在对象的生命周期结束之前发生, 除非另有说明,否则行为是未定义的。 [注意:这适用 甚至是用于线程同步的互斥锁等对象。 — 尾注]

就库而言,成员函数可以访问对象,直到它返回。因此,除非明确授予权限,否则在此类调用中间销毁对象是未定义的。

【讨论】:

  • 但是函数调用作为一个单元算作“访问”吗? It doesn't for unique_ptr's deleter, apparently... 因此,我将其解释为对成员数据的实际访问。话虽如此,有趣的是这里有一个特定的规则,因为您希望它包含在不“访问”不存在的对象的一般规则中。我开始认为它有点未指定,或者至少可能模棱两可......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多