Указатели на самом деле не указывают на сами объекты? - PullRequest
0 голосов
/ 21 августа 2011

У меня есть вектор класса Foo и еще один вектор указателей, которые указывают на подмножество Foo в векторе.В настоящее время у меня есть функция, которая выбирает некоторые указатели из vector<Foo *> и удаляет их из vector<Foo>, который фактически содержит их.Таким образом, вначале два вектора выглядят так:

//Foo classes in vector<Foo>
a
b
c
d

и

//Foo pointers in vector<Foo *>
*a
*b
*c
*d

Однако я обнаружил, что после удаления Foo, скажем b, онивыглядят так:

//Foo classes in vector<Foo>
a
c
d

и

//Foo pointers in vector<Foo *>
*a
*c
*d
*d

Почему указатель на c в vector<Foo *> не остается указанным на c после удаления bв vector<Foo>?Есть ли способ исправить это?

(я понимаю, что, если я удалю b, исходный указатель на b будет висящим; однако, поскольку я не собирался обращаться к bв любом случае после его удаления я подумал, что это не имеет значения, и я могу перейти к следующему индексу с указателем на c)

РЕДАКТИРОВАТЬ:

По запросу, код, где указатель вектора заполнен:

for(int i = 0; i < a.size(); i++) //a is the vector<Foo>
{
    Foo * thisFoo = &a[i];
    if(someConditionMet)
        b.push_back(thisFoo); //b is the vector<Foo *>
}

Ответы [ 3 ]

3 голосов
/ 21 августа 2011

A vector хранит свои элементы в массиве. Массив - это непрерывная последовательность элементов.

Если у вас есть vector содержащий элементы a, b, c, d и удаляем элемент b, то элементы c и d перемещаются вниз на один индекс в массиве, чтобы заполнить отверстие, созданное удаленным элементом, оставляя массив, содержащий a, c, d.

Указатели не «следуют» за элементами в vector при их перемещении. Если у вас есть указатель «на c», этот указатель действительно указывает на «элемент с индексом 2 в массиве». Когда вы удаляете b из массива, «элемент с индексом 2» будет тогда d, а не c.

Если вы хотите, чтобы у объекта был фиксированный адрес, который никогда не изменяется, вы должны динамически распределить его самостоятельно и отслеживать его с помощью интеллектуального указателя (например, unique_ptr или shared_ptr).

2 голосов
/ 21 августа 2011

Если вы хотите достичь чего-то подобного, вы не сможете использовать vector<foo>, чтобы фактически управлять самими foo объектами.Мне кажется, ваш субвектор foo* должен указывать на память, за которую отвечает vector<foo>.(Таким образом, именно поэтому вы все еще видите дополнительный указатель в конце, который указывает на d, и у вас все еще есть длина 4).

Мне кажется, что вы действительно хотите сделать, это использовать дваvector<foo*> и вручную создайте объекты, которые хранятся в первом, вместо того, чтобы сам вектор отвечал за объекты.Затем пусть ваш второй vector<foo*> просто скопирует указатели на объекты, которые вы создали.Таким образом, когда вы удаляете элемент из первого vector<foo*>, он удалит только его копию указателя, и ваш второй vector<foo*> не будет затронут.

Подумайте об этом без включенного вектора:

// create the initial storage for all the foo
foo* fooarray = new foo[foo_count];

// create all the foos for the array
for (int i=0; i < foo_count; ++i)
   fooarray = new foo();

// get a pointer to a subset of foo 
foo* foo_subset_pointer = &fooarray[10];

// make a list of a subset of the fooarray pointers
foo* foo_subset_list = new foo[10];
for (int i=0; i < 10; ++i)
    foo_subset_list = fooarray[i];

Итак, теперь, когда вы удаляете элемент из fooarray: у

// remove fooarray[3]
delete fooarray[3]; 
for (int i=4; i < 20; ++i)
   fooarray[i-1] = fooarray[i];

foo_subset_pointer будет удален исходный элемент 3, так как он был просто указателем на существующий массив.(И если вы получите доступ к foo_subset_pointer[19], он все равно будет иметь указатель на то же самое, что и foo_subset_pointer[18], потому что элементы не были обнулены ...)

Но что еще хуже, foo_subset_list[3] все еще указываетисходное местоположение: но это неверно, потому что он был удален!Вот почему вы не хотите, чтобы вектор отвечал за элементы списка, когда вы имеете дело с подмножеством, которое вы хотите сохранить.

Вместо этого звучит так, будто вы хотите, чтобы ваш первый вектор выполнял только удаление элемента (цикл for выше), но не delete.В этом случае он оставляет ваш foo_subset_list[3] нетронутым и все еще указывает на действительный foo.Дополнительная трудность заключается в том, что теперь вы должны обязательно выполнить delete foo_subset_list[3]; в какой-то момент в будущем.Но это позволяет вам вести себя так, как вы хотели.

1 голос
/ 21 августа 2011

Когда объект в vector удаляется, все объекты с большими индексами в vector перемещаются вниз, чтобы закрыть «дыру». Указатели на любой из этих объектов становятся недействительными. Единственный способ обнаружить ситуацию - это не попасть в нее в первую очередь - не хранить указатели на объекты не в const vector с, потому что это опасно.

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