Почему std :: begin и std :: end "не безопасны для памяти"? - PullRequest
0 голосов
/ 11 февраля 2019

В этом блоге Эрик Ниблер утверждает, что:

Что не так с std :: begin и std :: end?Сюрприз!они не безопасны для памяти.Рассмотрим, что делает этот код:

extern std::vector<int> get_data();
auto it = std::begin(get_data());
int i = *it; // BOOM

std :: begin имеет две перегрузки для константных и неконстантных l-значений.Проблема в том, что rvalues ​​связываются с константными lvalue ссылками, что приводит к висячему итератору, указанному выше.

Мне трудно понять его точку зрения и почему it является висячей ссылкой.Может кто-нибудь объяснить?

Ответы [ 6 ]

0 голосов
/ 14 февраля 2019

на самом деле сложную функцию можно упростить до двух коротких функций, таких как

int& foo(int x){
   return x;
}
int generate_a_int(){
   return 42;
}

, а затем вызвать ее foo (generate_a_int ()), временное значение генерируется, как только выходит из функцииbody, временное значение, сгенерированное функцией generate_a_int (), это destroy, а затем ссылка на мотаться произошла ...

теперь вы понимаете?

0 голосов
/ 12 февраля 2019

Потому что это позволяет инициализацию из значения r, что плохо.

0 голосов
/ 12 февраля 2019

Справедливо ли говорить, что это сбой безопасности памяти в std :: begin?Не существует «безопасного» способа создания итератора, который позволял бы следовать указателю после удаления контейнера.

В нем отсутствует проверка, которую имеет другой метод, но это не так, как нет способачтобы сделать итератор производным от диапазонов.Тебе просто нужно немного постараться ...

0 голосов
/ 11 февраля 2019

Я думаю, что смысл Эрика в отношении std::begin состоит в том, что он молча принимает контейнер значения в качестве аргумента для начала.На первый взгляд, проблема с кодом также проиллюстрирована в

auto it = get_data().begin();

Но std::begin - это бесплатный шаблон функции, его можно сделать, чтобы отклонять значения без необходимости добавлять соответствующие ссылочные квалификаторы вbegin членов каждого контейнера.«Просто» переадресация упускает возможность добавить уровень безопасности памяти в код.

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

template< class C > 
void begin( C&& ) = delete;

Это могло бы привести к тому, что код в посте блога был отклонен на месте.

0 голосов
/ 11 февраля 2019

Временный вектор, возвращаемый get_data, выходит из области действия после выполнения std::begin.Он не поддерживается, поэтому it является итератором в уничтоженном объекте.

0 голосов
/ 11 февраля 2019

Функция get_data возвращает объект.При использовании показанного выше способа этот объект будет временным объектом, который будет уничтожен после завершения полного выражения.Теперь итератор ссылается на векторный объект, который больше не существует и не может быть разыменован или использован любым полезным способом.

...