Печать вектора reference_wrapper <int> - PullRequest
2 голосов
/ 26 марта 2020

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

#include <algorithm>
#include <vector>
#include <iostream>

int main() {

    std::vector<int> vs{1, 2, 4, 5};

    std::vector<std::reference_wrapper<int>> vs1;

    for (int i : vs) {
        std::cout << "loop: " << i << std::endl;
        vs1.emplace_back(i);
    }

    for (auto p : vs1) {
        std::cout << p << std::endl;
    }
    return 0;
}

Вы можете подключить его к https://rextester.com/l/cpp_online_compiler_clang (или локально). Результат:

loop: 1
loop: 2
loop: 4
loop: 5
5
5
5
5
  1. Я бы ожидал 1,2,4,5, а не 5 на всем пути.
  2. Код не будет работать на неклангах , Где проблема?

Ответы [ 3 ]

4 голосов
/ 26 марта 2020

i является локальной переменной внутри ее объявления for l oop. Это копия каждого int в векторе vs. Таким образом, вы (посредством вызова emplace_back()) создаете reference_wrapper объекты, которые ссылаются на локальную переменную, сохраняя ссылки живыми после того, как закончится время жизни ссылочной переменной (i). Это неопределенное поведение .

Исправление заключается в том, чтобы i был ссылкой на каждый int, а не копией , таким образом reference_wrapper s относятся к int s в vs, как и ожидалось:

for (int& i : vs)
3 голосов
/ 26 марта 2020

Сначала вы забыли заголовок <functional>. Во-вторых, reference_wrapper<int> сохраняет ссылку на int. Не его ценность. Итак, в этом l oop:

for (int i : vs) {
    std::cout << "loop: " << i << std::endl;
    vs1.emplace_back(i);
}

Вы меняете значение i, но не его место в памяти. Это всегда одна и та же переменная. Вот почему он печатает последнее значение, хранящееся в этой переменной, которое является 5.

1 голос
/ 26 марта 2020

Вы можете представить себе этот диапазон на основе l oop

for (int i : vs) {
    std::cout << "loop: " << i << std::endl;
    vs1.emplace_back(i);
}

следующим образом

for ( auto first = vs.begin(); first != vs.end(); ++first )
{
    int i = *first;
    vs1.emplace_back(i);
}

, который находится в пределах l oop, с которым вы имеете дело переменная i, которая не будет жива после выхода из l oop.

Вам необходимо использовать ссылку на элементы вектора, такие как

for (int &i : vs) {
    std::cout << "loop: " << i << std::endl;
    vs1.emplace_back(i);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...