Вопрос по c++, stl, vector – std :: copy и std :: vector задача

5

Я понимаю, почему это вызывает segfault:

#include <algorithm>
#include <vector>
using namespace std;

int main()
{
    vector<int> v;
    int iArr[5] = {1, 2, 3, 4, 5};
    int *p = iArr;

    copy(p, p+5, v.begin());

    return 0;
}

Но почему это не вызывает segfault?

#include <algorithm>
#include <vector>
using namespace std;

int main()
{
    vector<int> v;
    int iArr[5] = {1, 2, 3, 4, 5};
    int *p = iArr;

    v.reserve(1);
    copy(p, p+5, v.begin());

    return 0;
}
или в этом случае v.assign (p, p + 5); stefaanv
или конструктор: vector <int> v (p, p + 5); Martin York
Почему бы тебе просто не использоватьcopy(p, p+5, back_inserter(v)); и избежать всего этого беспорядка? John Dibling
Был хороший ответ, связанный с различными видами неопределенного поведения в C ++:stackoverflow.com/questions/367633/... Sergei Kurenkov
@KennyTM 2-ое резервное пространство для 1 элемента BЈовић

Ваш Ответ

6   ответов
0

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

Оба не правы.

2

Потому что звезды выровнены. Или вы работали в режиме отладки, и компилятор сделал что-то, чтобы «помочь» вам. Суть в том, что вы делаете неправильную вещь и перешли в темный и недетерминированный мир неопределенного поведения. Выreserve одна точка в векторе, а затем попытаться втиснуть 5 элементов вreserveпространство. Плохой.

У вас есть 3 варианта. В моем личном порядке предпочтения:

1) Используйтеback_insert_iterator который предназначен именно для этой цели. Это обеспечивается#include <iterator>, Синтаксис немного причудливый, но, к счастью, хороший ярлык с сахарной оболочкой,back_inserter также предоставляется:

#include <iterator>
// ...
copy( p, p+5, back_inserter(v) );

2)assign элементы к вектору. Я предпочитаю этот метод чуть менее просто, потому чтоassign является членомvectorи это кажется мне немного менее общим, чем использование somethign изalgorithm.

v.assign(p, p+5);

3)reserve нужное количество элементов, затем скопируйте их. Я считаю, что это последний шаг на случай, если все остальное не получится по какой-либо причине. Это зависит от того факта, чтоvectorхранилище является смежным, поэтому оно не является универсальным, и это просто похоже на секретный метод передачи данных вvector.

7

и другое неправильно, поскольку вы копируете в пустой вектор, а для копирования требуется место для вставки. Он не изменяет размер контейнера сам по себе. Здесь вам, вероятно, понадобятся back_insert_iterator и back_inserter:

copy(p, p+5, back_inserter(v));
7

reserve() выделяет буфер дляпо крайней мере один элемент и элемент остается неинициализированным.

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

Суть в том - не делай этого. Доступ только к элементам, которые законно хранятся вvector пример.

Я понял. Я долженresize() вместоreserve(), Какая разница между двумя? nakiya
@nakiya: ключ, который вы должны спроситьvector выделить достаточно большой буфер, в противном случае это UB. sharptooth
@ Стив Джессоп: Да, ты прав. Даже если в хранилище типов есть какой-то указатель T *, просто читать их будет UB. Я обновил ответ. sharptooth
@ Стив Джессоп: Смущает, мягко говоря. :) РЕДАКТИРОВАТЬ: понял. nakiya
0

было бы неправильно даже копировать 1 элемент в вектор таким образом (или резервировать 5, а затем копировать таким образом).

Причина, по которой он, скорее всего, не является причиной ошибки, заключается в том, что разработчик посчитал, что было бы неэффективно выделять память только для одного элемента на тот случай, если вы захотите увеличить его позже, поэтому, возможно, они выделены достаточно для 16 или 32 элементов.

Выполнение резерва (5) сначала, а затем запись в 5 элементов напрямую, вероятно, не будет неопределенным поведением, но будет неправильным, поскольку вектор не будет иметь логического размера 5, а копия будет почти «потрачена впустую», поскольку вектор будет утверждать, что все еще имеет размер 0.

Правильным поведением будет резерв (5), вставьте элемент, сохраните где-нибудь его итератор, вставьте еще 4 элемента и посмотрите на содержимое первого итератора. Reserve () гарантирует, что итераторы не станут недействительными до тех пор, пока вектор не превысит этот размер, или пока не будет выполнен вызов, такой как erase (), clear (), resize () или другой reserve ().

2

которой вы не владеете, даже если это работает в примере. Я думаю, причина в том, чтоstd::vector будет резервировать более одного элемента.

Похожие вопросы