简体   繁体   English

boost :: combine()是否与方法的输出一起工作?

[英]Does boost::combine() work with output of a method?

In the test case below, I use boost::combine to iterate on output of a function getPoints() . 在下面的测试用例中,我使用boost :: combine来迭代函数getPoints()输出。

Expected Output 预期产出

I expect (1, 2, 3) printed 6 times; 我希望(1,2,3)打印6次; since I effectively zip two lists - 因为我有效拉链两个列表 -

([point, point, point], [point, point, point]). ([point,point,point],[point,point,point])。

Actual Output 实际产出

The output is surprising to me, and wrong. 输出对我来说是令人惊讶的,也是错误的。 The first two lines are off suggesting memory corruption? 前两行是关闭表明内存损坏?

(0, 0, 3)          // <-- wrong!
(52246144, 0, 3)   // <-- wrong! memory corruption?
(1, 2, 3)
(1, 2, 3)
(1, 2, 3)
(1, 2, 3)

This can also be verified online here, http://cpp.sh/622h4 . 这也可以在这里在线验证, http://cpp.sh/622h4

Is this a bug? 这是一个错误吗?

Code below - 代码如下 -

#include <iostream>
#include <vector>

#include <boost/range/combine.hpp>


struct Point {
    int x, y, z;
};

const std::vector<Point> getPoints() {
    // There is only one Point in the entire code, which is (1, 2, 3).
    const Point point = {1, 2, 3};
    // Return a vectore of 3 copies of the point (1, 2, 3).
    return {point, point, point};
}


int main() {
    // Zip over two copies of 3-tuples of {1, 2, 3}.
    for (const auto& zipped : boost::combine(getPoints(), getPoints())) {
        auto p1 = zipped.get<0>();
        auto p2 = zipped.get<1>();
        // Expected output is (1, 2, 3), six times.
        std::cout << "(" << p1.x << ", " << p1.y << ", " << p1.z << ")" << std::endl;
        std::cout << "(" << p2.x << ", " << p2.y << ", " << p2.z << ")" << std::endl;
    }

    return 0;
}

You have undefined behavior here as you access a dangling reference. 当您访问悬空引用时,此处有未定义的行为。 This can be fixed by 这可以修复

const auto points1 = getPoints();
const auto points2 = getPoints();

for (const auto& zipped : boost::combine(points1, points2)) {
    // ...
}

Rvalue references are always problematic when dealing with range libraries. 在处理范围库时,Rvalue引用总是有问题的。 Obviously, a range algorithm like boost::combine doesn't copy the argument. 显然,像boost::combine这样的范围算法不会复制参数。 And it creates a new proxy range object, which makes it impossible to extend the lifetime of the temporary range passed in. 它创建了一个新的代理范围对象,这使得无法延长传入的临时范围的生命周期。

Contrary, a range-based for loop for(const auto& item: getPoints()) {...} expands to 相反, for(const auto& item: getPoints()) {...}的基于范围的for循环扩展为

{
    auto && __range = getPoints();
    for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement
    }
} 

where the lifetime of getPoints() is extended by binding it to an rvalue reference. getPoints()的生命周期通过将其绑定到右值引用来扩展。 Imagine a function template combine as 想象一下功能模板combine

template<class Rng>
auto combine(Rng&& rng) {
    auto && == range; // Nice try but doesn't help

    // ...

    return someProxyRange;
}

This function template can't do anything about extending the lifetime of rng , as it acts in a different scope than rng , which comes from the client side. 此函数模板无法延长rng的生命周期,因为它的行为与rng不同,后者来自客户端。 In a range based for loop, this is different. 在基于循环的范围中,这是不同的。 The scope of the temporary (eg getPoints() ) and the forwarding reference auto&& __range are at the same scope, hence the lifetime can be extended. 临时(例如getPoints() )和转发引用auto&& __range的范围在同一范围内,因此可以延长生命周期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM