Работает ли boost :: comb () с выводом метода - PullRequest
3 голосов
/ 04 апреля 2019

В приведенном ниже тесте я использую boost :: comb для повторения вывода функции getPoints().

Ожидаемый результат

Я ожидаю (1, 2, 3) напечатано 6 раз; так как я эффективно архивирую два списка -

([точка, точка, точка], [точка, точка, точка]).

Фактический объем производства

Вывод для меня неожиданный и неправильный. Первые две строки выключены, предполагая повреждение памяти?

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

Это также можно проверить онлайн здесь, http://cpp.sh/622h4.

Это ошибка?

код ниже -

#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;
}

1 Ответ

2 голосов
/ 04 апреля 2019

У вас есть неопределенное поведение здесь, когда вы получаете доступ к свисающей ссылке. Это можно исправить с помощью

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

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

Rvalue ссылки всегда проблематичны при работе с библиотеками диапазонов. Очевидно, что алгоритм диапазона, такой как boost::combine, не копирует аргумент. И он создает новый объект диапазона прокси, который делает невозможным продление времени жизни переданного временного диапазона.

Наоборот, диапазон для цикла for(const auto& item: getPoints()) {...} расширяется до

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

        range_declaration = *__begin;
        loop_statement
    }
} 

, где время жизни getPoints() увеличивается путем привязки его к rvalue-ссылке. Представьте себе шаблон функции combine как

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

    // ...

    return someProxyRange;
}

Этот шаблон функции ничего не может поделать с продлением времени жизни rng, так как он действует в другой области действия, чем rng, что исходит со стороны клиента. В диапазоне, основанном на цикле, это отличается. Объем временного (например, getPoints()) и ссылки переадресации auto&& __range находятся в той же области, следовательно, срок службы может быть продлен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...