C++0x 闭包的未定义行为:II

2024-01-23

我发现 C++0x 闭包的使用令人困惑。我的初始report https://stackoverflow.com/questions/5543169/how-to-make-a-vector-of-functors-lambdas-or-closures-in-cox/5556376#5556376,以及后续一个 https://stackoverflow.com/questions/5556183/make-c-crash-without-casting/5557843#5557843,产生的混乱多于解释。下面我将向您展示麻烦的示例,希望找出代码中存在未定义行为的原因。所有代码片段都通过了 gcc 4.6.0 编译器,没有任何警告。

方案 1:有效

#include <iostream>
int main(){
    auto accumulator = [](int x) {
        return [=](int y) -> int { 
            return x+y;
        }; 
    };
    auto ac=accumulator(1);
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}

输出结果满足预期:

2 2 2

2 2 2

2 2 2

2. 方案 2:关闭,运行良好

#include <iostream>
int main(){
    auto accumulator = [](int x) {
        return [&](int y) -> int { 
            return x+=y;
        }; 
    };
    auto ac=accumulator(1);
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}

输出是:

4 3 2

7 6 5

10 9 8

程序 3:带有 std::function 的程序 1,工作正常

#include <iostream>
#include <functional>     // std::function

int main(){

    typedef std::function<int(int)> fint2int_type;
    typedef std::function<fint2int_type(int)> parent_lambda_type;

    parent_lambda_type accumulator = [](int x) -> fint2int_type{
        return [=](int y) -> int { 
            return x+y;
        }; 
    };

    fint2int_type ac=accumulator(1);

    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}   

输出是:

2 2 2

2 2 2

2 2 2

程序 4:带有 std::function 的程序 2,未定义行为

#include <iostream>
#include <functional>     // std::function

int main(){

    typedef std::function<int(int)> fint2int_type;
    typedef std::function<fint2int_type(int)> parent_lambda_type;

    parent_lambda_type accumulator = [](int x) -> fint2int_type{
        return [&](int y) -> int { 
            return x+=y;
        }; 
    };

    fint2int_type ac=accumulator(1);

    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}

程序的第一次运行给出:

4 3 2

4 3 2

12364812 12364811 12364810

第二次运行同一程序:

4 3 2

4 3 2

1666060 1666059 1666058

第三个:

4 3 2

4 3 2

2182156 2182155 2182154

我对 std::function 的使用如何破坏代码?为什么程序 1 - 3 运行良好,而程序 4 在调用 ac(1) 三次(!)时正确?为什么程序 4 在接下来的三种情况下陷入困境,就好像变量 x 是通过值而不是引用捕获的一样。 ac(1) 的最后三个调用是完全不可预测的,就好像对 x 的任何引用都会丢失一样。


我希望找出为什么有 代码中未定义的行为

每次处理复杂的 lambda 时,我都觉得首先将其转换为函数对象形式会更容易。因为 lambda 只是函数对象的语法糖,并且对于每个 lambda 都存在与相应函数对象的一对一映射。这篇文章很好地解释了如何进行翻译:http://blogs.msdn.com/b/vcblog/archive/2008/10/28/lambdas-auto-and-static-assert-c-0x-features-in-vc10-part-1.aspx http://blogs.msdn.com/b/vcblog/archive/2008/10/28/lambdas-auto-and-static-assert-c-0x-features-in-vc10-part-1.aspx

例如,您的程序 2 :

#include <iostream>
int main(){
    auto accumulator = [](int x) {
        return [&](int y) -> int { 
            return x+=y;
        }; 
    };
    auto ac=accumulator(1);
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}

编译器大约会翻译成这样:

#include <iostream>

struct InnerAccumulator
{
    int& x;
    InnerAccumulator(int& x):x(x)
    {
    }
    int operator()(int y) const
    {
        return x+=y;
    }
};

struct Accumulator
{
    InnerAccumulator operator()(int x) const
    {
        return InnerAccumulator(x); // constructor
    }
};


int main()
{
    Accumulator accumulator;
    InnerAccumulator ac = accumulator(1);
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
    std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl;
}

现在,问题变得非常明显:

InnerAccumulator operator()(int x) const
{
   return InnerAccumulator(x); // constructor
}

这里 InnerAccumulator 的构造函数将引用 x,这是一个局部变量,一旦退出operator() 作用域,它就会消失。所以是的,正如您所怀疑的那样,您只会得到一个简单的、良好的、未定义的行为。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++0x 闭包的未定义行为:II 的相关文章

  • alignas() 对 sizeof() 的影响 - 强制吗?

    这个程序 struct alignas 4 foo int main return sizeof foo 返回 4 其中 GCC 10 1 和 clang 10 1 以及 icc 19 0 1 这让我想知道 这是强制性的alignas 影响
  • 每次迭代时在 for 循环中计算向量大小是否昂贵?

    C 编译器是否处理诸如建筑物是向量之类的情况 for int i 0 i lt buildings size i 也就是说 它是否注意到建筑物是否在循环中被修改 然后 基于此不评估它每次迭代 或者也许我应该自己做这件事 不是那么漂亮但是 i
  • Expression.Property 的 Expression.Convert 类型

    我正在尝试转换参数表达式 但在转换为值类型时遇到问题 下面是我的代码示例 public static MemberExpression ConvertToType ParameterExpression sourceParameter Pr
  • 在编译时使用 Constexpr 填充数组

    我想使用 constexpr 填充枚举数组 数组的内容遵循一定的模式 我有一个枚举 将 ASCII 字符集分为四类 enum Type Alphabet Number Symbol Other constexpr Type table 12
  • 如何在 CF10 中确定闭包变量的范围?

    引自Adobe ColdFusion 10 使用闭包文档 http help adobe com en US ColdFusion 10 0 Developing WSe61e35da8d31851842acbba1353e848b35 8
  • C++,set_terminate 是每个线程本地的吗?

    Should set terminate get terminate在 C 2011 或 C 2003 中为多个线程设置不同的终止异常处理器 例如 如果我有程序并将终止处理程序设置为func 1 然后我启动3个线程 新线程中的终止处理程序是
  • 为什么在创建矩阵类时使用向量不好?

    对于我的矩阵类 我做了 template
  • C++0x中disable_if在哪里?

    Boost 两者都有enable if and disable if 但 C 0x 似乎缺少后者 为什么它被排除在外 C 0x 中是否有元编程工具允许我构建disable if按照enable if 哦 我刚刚注意到std enable i
  • 将 N 种类型的参数包折叠成 N-1 对

    我正在尝试折叠参数包N不同类型分为std tuple of N 1 std pairs与各自的类型 例如表达式 ResolveToTupleOfPairs
  • 检查 Objective-C 块类型?

    这主要是出于好奇 我不太确定它的实际用途是什么 但就这样吧 由于块也是 Objective C 对象 是否可以检查它们的类型 也就是说 它是否响应isKindOfClass 消息以及如何使用该消息来处理块 我天真的以为事情大概是这样的 vo
  • Java 拥有闭包后 Scala 的优势 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 随着 Java 中添加了闭包 作为语言选择 Scala 相对于 Java 的优势是什么 有人可以详细说明一下有什么优点吗 除了闭包 J
  • 类模板专业化优先级/歧义

    在尝试依赖可变参数模板实现一些东西时 我偶然发现了一些我无法解释的东西 我将问题归结为以下代码片段 template
  • 如何确定 std::function 的参数数量?

    我有以下问题 假设您想编写一个可以采用 lambda 表达式的通用函数 我知道如果参数是 std function 类型 那么我不仅可以使用 lambda 还可以使用函数 甚至可以使用函数指针 所以第一步 我做了以下事情 void prin
  • Haskell - lambda 表达式

    我试图了解什么是有用的以及如何在 Haskell 中实际使用 lambda 表达式 我不太明白使用 lambda 表达式相对于定义函数的约定方式有何优势 例如 我通常会执行以下操作 let add x y x y 我可以简单地打电话 add
  • 不明白 Swift 中的闭包示例

    我正在尝试了解 swift 和闭包 我被这个例子困住了 numbers map number Int gt Int in let result 3 number return result 什么是 number Int gt Int 它是一
  • 在 C++11 中省略返回类型

    我最近发现自己在 C 11 模式下的 gcc 4 5 中使用了以下宏 define RETURN x gt decltype x return x 并编写这样的函数 template
  • 是否允许将 std::vector 的元素插入到同一向量中?

    考虑以下insert and emplace的成员函数std vector
  • C++11 Geany 设置

    我正在学习 C 我需要在 Geany 中为 C 11 正确设置编译和构建命令 我以为我的理解是正确的 但是当使用时auto 我收到以下错误 warning auto will change meaning in C 0x please re
  • 使用 lambda 表达式注册类型

    我想知道如何在 UnityContainer 中实现这样的功能 container RegisterType
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string

随机推荐

  • from __future__ import ... 能否保证 Python 2 和 3 的兼容性?

    我对热身 Python 2 还是 Python 3 不感兴趣 问题 尽管最近的一个 https stackoverflow com q 5478518 321973我发现已经一岁多了 但我偶然发现 如果您的文件开始 您可以在 Python
  • 如何清除 Objective-C 中常驻的脏内存?

    我观看了 Apple 的 WWDC 2010 视频 Advanced Memory Analysis with Instruments 从中我发现了大量常驻脏内存 我意识到拥有如此多的常驻脏内存是一件坏事 这可能是我的应用程序崩溃的原因 但
  • 我们可以在 Java 中将两种字体样式组合在一起吗?

    我正在尝试更改 a 的字体JLabel所以两者都是BOLD and ITALIC 但似乎没有定义静态字段来执行此操作 我们如何将两种样式结合起来以获得粗斜体字体 此代码将通过使用静态字段以粗体形式完成此操作BOLD 但没有为粗体和斜体定义字
  • CKeditor 添加类到 img 标签

    我正在尝试向 CKeditor 中任何插入的 img 标签添加一个类 我尝试了各种方法 但似乎无法弄清楚这个插件的设置是如何工作的 虽然文档很多 但只提到需要添加代码 但没有提到应该添加到哪里 文件很多 我尝试将其添加到 config js
  • google.script.host.close 关闭对话框不起作用

    我正在尝试关闭用以下命令打开的无模式对话框 var html HtmlService createHtmlOutputFromFile dialog setSandboxMode HtmlService SandboxMode IFRAME
  • Symfony 4 Doctrine 无法从控制台运行 [2002] 没有这样的文件或目录

    我正在使用 symfony 4 运行学说控制台命令时会发生此错误 In AbstractMySQLDriver php line 108 An exception occurred in driver SQLSTATE HY000 2002
  • 添加自定义目录(源和规范)以在 Rails 3 项目中进行自动测试

    我有一个 Rails 3 应用程序 它使用 RSpec2 作为我的测试框架 并且我能够使用自动测试来观察我的模型和规范目录的更改 并在文件更改时重新运行我的规范套件 我想添加一个目录 其中包含一些自定义类 RAILS ROOT lib so
  • For循环和if语句

    我正在使用以下 for 循环 for int intPrjName 0 intPrjName lt arrPrjName count intPrjName 我在 for 循环下有一个 if else 语句 其中else块显示警报消息 假设数
  • onNavigationItemSelected 在 NavigationView 中不起作用

    请有人帮助我处理导航抽屉中的片段 由于某种原因我无法让它们工作并且所有代码看起来都是正确的 Here https github com Matt Hutchings The Midlands Meander是源代码的链接 使用此代码 nav
  • 使用 angularjs/ui-bootstrap 制作手风琴并使用 ng-model

    我使用 angularJs 和 bootstrap 我制作了一个手风琴 其中我放置了一个选择来选择过滤器的值和不起作用的 data ng model 如果他不在手风琴中 则选择可以工作 这是我的代码
  • 在没有指针的函数中使用函数原型

    我的导师提到在其他函数中使用函数作为参数 我不是说使用指针 这可能吗 我在下面显示 我不明白他做了什么 谁能用例子解释一下吗 谢谢大家的赞赏回答 使用风格是 int test double abc double bla bla 函数是 do
  • C# 中的猴子修补

    是否可以在运行时扩展或修改 C 类的代码 我的问题具体围绕 Monkey Patching Duck Punching 或元对象编程 MOP 就像 Groovy Ruby 等脚本语言中发生的那样 对于那些今天仍然在这个问题上绊倒的人来说 确
  • SVN 显示日志不起作用

    如何在不设置 r 向所有人 所有内容读取 的情况下使用显示日志功能 我的 authz 文件中有几个组 它看起来像这样 groups Profs dave bruno franck Team1 1036091 1036103 1036087
  • 从 BeautifulSoup 结果中获取表单“action”

    我正在为一个网站编写一个 Python 解析器来自动完成一些工作 但我不太喜欢 Py 的 re 模块 正则表达式 并且无法使其工作 req urllib2 Request tl2 req add unredirected header Us
  • 什么时候抛出异常?

    异常是美妙的事情 但有时我担心我抛出太多异常 考虑这个例子 类用户 public function User user Query database for user data if user throw new ExistenceExce
  • C++ 中的异步线程安全日志记录(无互斥体)

    我实际上正在寻找一种在我的 C 中进行异步和线程安全日志记录的方法 我已经探索过 log4cpp log4cxx Boost log 或 rlog 等线程安全日志记录解决方案 但似乎它们都使用互斥锁 据我所知 互斥体是一种同步解决方案 这意
  • 如何在android中将位图转换为PDF格式[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我在 thepic 变量中有位图 它是位图类型 imageUri Uri intent getParcelableExtra Intent
  • C++11 类型推断期间控制优先级的规则是什么?

    管理 float double 类型的 C 11 类型推断的优先级规则是什么 例如 当从包含多种类型的表达式进行推断时 如下所示 auto var float 1 double 1 结果将是double 这就是所谓的floating poi
  • 如何在 Matplotlib 中反转轴并设置极坐标图的零位置?

    使用 Matplotlib 极坐标图时 theta 轴默认零位置为 或 右侧 角度逆时针增大 如下所示这个例子 https matplotlib org examples pylab examples polar demo html 如何指
  • C++0x 闭包的未定义行为:II

    我发现 C 0x 闭包的使用令人困惑 我的初始report https stackoverflow com questions 5543169 how to make a vector of functors lambdas or clos