std :: reference_wrapper вокруг * этого - PullRequest
4 голосов
/ 07 марта 2019

У меня есть сценарий, в котором мне нужно преобразовать функцию, которая может быть прикована цепью *this к возвращению std::optional<std::reference_wrapper<T>> вместо T& (причина выходит за рамки этого вопроса). Причина, по которой я использую std::reference_wrapper, заключается в том, что std::optional не может получить ссылку, по крайней мере, в C ++ 11. Однако, это не работает, потому что я, кажется, сталкиваюсь с проблемами при жизни. Вот минимальный пример:

#include <iostream>
#include <functional>

struct test {
    std::reference_wrapper<test> foo() {
        val = 42;
        return *this;
    }

    test& foo2() {
        val = 50;
        return *this;
    }

    int val;
};

void bar(test t) {
    std::cout << std::move(t).val << "\n";
}

int main()
{
    auto f = test().foo();
    bar(f);
    auto g = test().foo2();
    bar(g);
}

Это выводит 0 50 вместо ожидаемого 42 50. Если я разделю это на два утверждения:

auto f = test();
auto f2 = f.foo();
bar(f2);

Работает как положено. Используя отладчик, я обнаружил, что компилятор оптимизирует некоторые выражения, и val остается неинициализированным, что заставляет меня думать, что в моем коде есть неопределенное поведение.

Есть ли у меня неопределенное поведение? Если да, то как мне избежать этого здесь?

Ответы [ 2 ]

5 голосов
/ 07 марта 2019

Есть ли у меня неопределенное поведение?

Да.auto выводит тип объекта из выражения, использованного для его инициализации.И вы используете выражение типа std::reference_wrapper<test> для инициализации f.Временное значение test() исчезает после инициализации f, поэтому f немедленно свисает.

Вы можете либо разделить объявление, как вы уже сделали, либо использовать функцию-член std::references_wrappers get:

auto f = test().foo().get();

В любом случае, std::reference_wrapper<test> не является заменой ссылки во всех контекстах, поддерживаемых C ++.Прокси-объекты никогда не бывают.

3 голосов
/ 07 марта 2019

Есть ли у меня неопределенное поведение?

Да. Посмотрите на линию auto f = test().foo();. f - это std::reference_wrapper<test>, а экземпляр test, на который он ссылается, - test(). Время жизни test() заканчивается прямо в конце этой строки, и вы получите висячую ссылку. Это не относится к auto g = test().foo2();, так как он копирует возвращаемое значение (спасибо @StoryTeller за помощь в этом).

как мне избежать этого здесь?

Вам необходимо отделить управление временем жизни от части std::reference_wrapper. Это будет работать:

test t;
auto f = t.foo();

// Do stuff with f until this scope ends.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...