Nano Hash - криптовалюты, майнинг, программирование

Указатели на самом деле не указывают на сами объекты?

В настоящее время у меня есть вектор класса 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 *>
}
21.08.2011

  • Пожалуйста, предоставьте код, в котором вы заполняете массив, это основная часть. 21.08.2011
  • Позвольте мне надеть мою экстрасенсорную шляпу. 21.08.2011

Ответы:


1

vector хранит свои элементы в массиве. Массив представляет собой непрерывную последовательность элементов.

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

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

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

21.08.2011
  • О, я вижу. Я забыл, что указатели просто указывают на место в памяти, а не следуют за самим фактическим объектом. 21.08.2011
  • @Tomalak: Ну, мои экстрасенсорные способности не особенно надежны. Тем не менее, мне нравится возможность попробовать их использовать. :-) 21.08.2011
  • Имейте в виду, что удаление элемента из std::vector может привести к его перераспределению, что сделает недействительными все указатели на его элементы. 21.08.2011
  • @Novelocrat: стирание никогда не может привести к перераспределению. 21.08.2011
  • В качестве альтернативы @wrongusername может переключиться на std::list. Удаление элементов из списка не приводит к перемещению следующих элементов. 21.08.2011
  • @Джеймс Макнеллис: Вы правы. Я думал, что стирание элементов позволяет перераспределить память, чтобы уменьшить объем памяти, но, похоже, это не так. 14.09.2011

  • 2

    Если вы хотите добиться чего-то подобного, вы не сможете использовать 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]; в какой-то момент в будущем. Но это позволяет вам вести себя так, как вы хотели.

    21.08.2011

    3

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

    21.08.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..