【问题标题】:How is the this pointer captured?this 指针是如何被捕获的?
【发布时间】:2014-02-02 19:28:34
【问题描述】:

考虑以下代码:

struct S
{
  int x;
  void f()
  {
    auto l = [&](){ x = 42; }; //this is implicitly captured here
  }
};

§5.1.2/14 规定:

如果实体被隐式捕获并且捕获默认值为 =,或者如果使用不包含 & 的捕获显式捕获实体,则该实体被复制捕获。

因此我得出结论,this 没有被副本捕获。但随后通过 §5.1.2/15:

如果实体被隐式或显式捕获但未通过副本捕获,则通过引用捕获实体。对于通过引用捕获的实体,是否在闭包类型中声明了其他未命名的非静态数据成员是未指定的。

this通过引用捕获。但现在 §5.1.2/17 规定:

[...] 如果this 被捕获,this 的每个 odr-use 都将转换为对闭包类型的相应未命名数据成员的访问,[...]

据我了解,这意味着在与this 指针对应的闭包类型中必须有一个未命名的数据成员。但是由于this通过引用捕获,因此标准不要求存在这样的成员。我怎么了?

【问题讨论】:

    标签: c++ c++11 lambda this


    【解决方案1】:

    标准没有明确说明,但this只能通过副本捕获。它不可能被左值引用捕获,因为this 是每个 C++11 §9.3.2/1 的右值。

    请注意,标准禁止通过引用显式捕获 this,因为 (a) 语法不允许 &this 在捕获列表中,因为 this 在词法上是关键字而不是标识符 , 和 (b) 5.1.2/8 禁止在默认捕获为 = 时显式捕获 this

    在默认捕获为&时可以隐式捕获this,这似乎是规范中的错误,表明它是通过引用捕获的。

    【讨论】:

    • 哪里说不能通过引用捕获右值?至少在 n3242 (我手头的)中,当通过引用捕获某些东西时,似乎完全没有说明会发生什么。特别是,引用的 5.1.2/15 并没有说“在闭包类型中声明了左值引用”,而是明确地未指定。
    • @rmcclellan 从语法上讲,您必须通过标识符来引用某些内容,以便显式或隐式捕获它。在 C++ 中指定右值的名称并不多:thisnullptr 浮现在脑海中。快速浏览一下 2.12/1 也会出现 truefalse。所有都由语法中的关键字指定。我想这是隐含的,用作关键字禁止它们匹配语法中的一般 identifier 产生?大概这就是为什么thiscapture的语法产生中是特殊的。
    • GCC 4.8.1 seems to concur with my suggestion that keywords are not identifiers。规范中有一个漏洞表明this 可以通过引用隐式捕获,尽管语法使得无法通过引用显式捕获它。
    • 在 N3242 5.1.2/11 中,它确实明确指出 this 可以被隐式捕获,并结合 5.1.2/15,似乎很清楚 this 可以被捕获参考。我同意你的观点,通过引用捕获 this 没有多大意义,而且可以说是一个错误。
    • A keyword is §2.12/1 中的 identifier。 §5.1.2/10 不正确地使用像 truenullptr 这样的关键字:“使用不合格名称查找的常用规则查找捕获列表中的标识符(3.4.1);每个此类查找都应找到一个在本地 lambda 表达式的到达范围内声明的具有自动存储持续时间的变量。"
    【解决方案2】:

    我认为您发现了一个规范错误 - 您是正确的,this 是通过引用捕获的,但您在 §5.1.2/17 中找到的文本应该仅适用于 this 被捕获复制。

    正如凯西所说,通过引用捕获 this 并没有多大意义。

    【讨论】:

      【解决方案3】:

      当然这样的数据成员存在于闭包类型中。按值捕获和按引用捕获都需要闭包类型中的数据成员。唯一的问题是它的类型:

      T /* maybe const and/or volatile */ * captured_this;
      

      T /* maybe const and/or volatile */ * const & captured_this;
      

      由于this 永远不会改变,因此两者之间没有明显的区别。

      【讨论】:

      • 虽然这对于健全的实现来说“显然”是正确的,但标准也明确没有强制要求。请参阅问题中 §5.1.2/15 的引用部分。
      • @rmcclellan:我认为引用的措辞旨在允许在通过引用捕获的多个变量相邻存储时仅存储单个地址。我会假设this 也允许优化:如果它可以从其他捕获的变量中计算出来,它可能不会单独存储。但是没有明显的区别(除非内存太紧以至于你担心闭包的内存消耗)
      • 我认为您对该措辞的意图是正确的,但是,与此同时,我在规范中看不到任何明确暗示该解释的内容。据我所知,通过引用捕获并没有完全指定。我想在规范中看到“通过引用捕获与按值捕获相同的方式,除了闭包成员是左值引用”。不过,我觉得这样的句子是不存在的。
      • 无论如何,如果确实如此,那么该规则将不允许通过引用捕获this,因为this 是纯右值并且无法初始化左值引用。
      • @rmcclellan:您无法使用this 初始化左值引用。实现不受此类限制。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 2019-11-11
      • 1970-01-01
      • 2016-04-25
      相关资源
      最近更新 更多