C++ lazy evaluation(延迟计算或惰性求值)介绍

      C++中的lazy evaluation or call-by-need(延迟计算或按需调用)是一种求值策略,其中表达式在第一次使用之前不求值,即将求值推迟到真正需要时

      为一个最终可能不需要的计算付出性能代价显然不是明智之举。然而在复杂的代码中这种情况比比皆是。我们不应该执行"只在某种情况下"才需要的昂贵计算,而应该只在必要的时候执行昂贵计算。这通常意味着把计算推迟到真正需要的时候才进行,因此称之为延迟计算或惰性求值。在C++中,对象的定义会调用构造函数和析构函数,这可能是高成本的,因为它导致了立即计算----而这正是我们所要避免的。延迟计算原则建议我们推迟对象的定义,直到要使用该对象时再定义。为不一定用到的构造函数和析构函数付出代价是没有意义的。不仅应该将对象的创建推迟至合适的位置,而且应该直到具备了一个有效创建操作所必需的全部条件后,再创建对象。

      当你使用了lazy evaluation后,采用此种方法的类将推迟计算工作直到系统需要这些计算的结果。如果不需要结果,将不用进行计算。

      在某些情况下要求软件进行原来可以避免的计算,这时lazy evaluation才是有用的。

      下面是两个采用lazy evaluation的测试代码段:

      1.通过引用计数减少不必要的拷贝:

int test_evaluation_1()
{
    // 引用计数: 除非你确实需要,否则不去为任何东西制作拷贝.我们应该是lazy的,只要有可能就共享使用其它值
    std::string str1 = "hello";
    std::string str2 = str1; // str2和str1指向同一块内存地址
    fprintf(stdout, "pointer: str1: %p, str2: %p\n", // pointer: str1: 0x2061208, str2: 0x2061208
        static_cast<void*>(const_cast<char*>(str1.c_str())), static_cast<void*>(const_cast<char*>(str2.c_str())));

    str2 = "beijing"; // str2被重新赋值后,str2和str1不在指向同一块内存地址
    fprintf(stdout, "pointer: str1: %p, str2: %p\n", // pointer: str1: 0x2061208, str2: 0x2061648
        static_cast<void*>(const_cast<char*>(str1.c_str())), static_cast<void*>(const_cast<char*>(str2.c_str())));

    return 0;
}

      2.矩阵运算中,在真正使用时才做运算,通过运算符重载实现:

using matrix = std::array<int, 2>;

// write this proxy
struct matrix_add {
    matrix_add(const matrix& a, const matrix& b) : a_(a), b_(b) { fprintf(stdout, "do nothing\n"); }

    // an implicit conversion operator from matrix_add to plain matrix
    // the evaluation takes place only when the final result is assigned to a matrix instance
    operator matrix() const {
        fprintf(stdout, "add operation\n");
        matrix result;
        for (int i = 0; i < 2; ++i)
            result[i] = a_[i] + b_[i];

        return result;
    }

    // calculate one element out of a matrix sum
    // it's of course wasteful to add the whole matrices
    int operator ()(unsigned int index) const {
        fprintf(stdout, "calculate *just one* element\n");
        return a_[index] + b_[index];
    }

private:
    const matrix& a_, b_;
};

// to make this function lazy, it's enough to return a proxy instead of the actual result
matrix_add operator + (const matrix& a, const matrix& b)
{
    return matrix_add(a, b);
}

int test_evaluation_2()
{
    // reference: https://stackoverflow.com/questions/414243/lazy-evaluation-in-c
    // 矩阵计算: 主要机制是运算符重载
    matrix mat1 = {2, 3}, mat2 = {7, 8};
    auto ret = mat1 + mat2;
    fprintf(stdout, "... ...\n");
    matrix mat3(ret); // implicit conversion from matrix_add to matrix

    fprintf(stdout, "one element sum: %d\n", ret(1));

    return 0;
}

      执行结果如下图所示:

      GitHub: https://github.com/fengbingchun/Messy_Test

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的惰性求值是指在需要计算结果时才进行计算,而不是在表达式被定义时就立即计算。这种求值策略可以节省计算资源,特别是在处理大量数据或复杂计算时非常有用。 Python中的生成器(Generator)和迭代器(Iterator)是常用的实现惰性求值的方式。生成器是一种特殊的函数,它使用yield语句来产生一个序列的值,每次yield返回一个值后,生成器函数的状态会被冻结,直到下一次调用继续执行。迭代器是实现了__iter__()和__next__()方法的对象,用于遍历数据集合。 通过使用生成器和迭代器,我们可以在需要时动态生成计算结果,而不必提前计算和存储所有结果。这在处理大型数据集或无限序列时非常有用,可以提高效率并减少内存占用。 下面是一个简单的示例,展示了如何使用生成器实现惰性求值: ```python def lazy_evaluation(): i = 0 while True: yield i i += 1 lazy_numbers = lazy_evaluation() # 创建生成器对象 print(next(lazy_numbers)) # 输出:0 print(next(lazy_numbers)) # 输出:1 print(next(lazy_numbers)) # 输出:2 ``` 在上面的例子中,我们定义了一个生成器函数`lazy_evaluation()`,它使用一个无限循环和yield语句来产生递增的整数序列。通过调用`next()`函数,我们可以逐个获取生成器产生的值,而不必一次性计算所有值。 总结来说,惰性求值是一种用于优化计算资源和处理大规模数据的技术,在Python中可以通过生成器和迭代器来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值