Можно ли удалить элементы из вектора shared_ptr? - PullRequest
1 голос
/ 27 апреля 2019

Скажите, у меня есть

vector<shared_ptr<string>> enemy;

как мне удалить элементы из вражеского вектора?

Заранее спасибо за помощь

** Правка (код в контексте)

void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
  int i = 0;
  bool found = FALSE;
  for(auto it = chart.begin(); it != chart.end(); i++)
  {
    if(id == chart[i]->GetEnemyID() )
    {
        found = TRUE;
        chart.erase(it);
    }
}

код выше segfaults me

Ответы [ 3 ]

1 голос
/ 27 апреля 2019

Вы удаляете элементы так же, как вы удаляете любые элементы из любого std::vector - например, с помощью метода std::vector::erase(). Все, что вам для этого нужно - это iterator до нужного элемента для удаления.

В вашем случае, поскольку вы храните std::shared_ptr<std::string> объекты, а не фактические std::string объекты, вам может понадобиться что-то вроде std::find_if(), чтобы найти элемент вектора, содержащий требуемое строковое значение Например:

void removeEnemy(string name)
{
    auto iter = std::find_if(enemy.begin(), enemy.end(),
        [&](auto &s){ return (*s == name); }
    );
    if (iter != enemy.end())
        enemy.erase(iter);
}

ОБНОВЛЕНИЕ: в новом коде, который вы добавили, вы неправильно смешиваете индексы и итераторы вместе. Вы создаете бесконечный цикл , если vector не пустой, так как вы никогда не увеличиваете итератор it, который контролирует ваш цикл, вы вместо этого увеличиваете свою переменную index i (смотрите, что происходит, когда Вы не даете своим переменным уникальные и значимые имена?). В итоге вы выходите за пределы vector в окружающую память. Вот почему вы получаете ошибку segfault.

Даже если вы (пытаетесь) использовать итератор для циклического перебора vector, вы используете индексы для доступа к элементам вместо разыменования итератора для доступа к элементам. В этой ситуации вам вообще не нужно использовать индексы, одного итератора будет достаточно.

Попробуйте вместо этого:

void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
  for(auto it = chart.begin(); it != chart.end(); ++it)
  {
    if (id == it->GetEnemyID() )
    {
      chart.erase(it);
      return;
    }
}

Или, используя код, который я предложил ранее:

void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
    auto iter = std::find_if(chart.begin(), chart.end(),
        [&](auto &enemy){ return (enemy->GetEnemyID() == id); }
    );
    if (iter != chart.end())
        chart.erase(iter);
}
0 голосов
/ 27 апреля 2019

Проблема с вашим кодом в том, что erase() делает недействительным итератор.Вы должны использовать it = chart.erase(it).

0 голосов
/ 27 апреля 2019

Мне нравится мой, который будет удалять инопланетян на высокой скорости и без какой-либо заботы о заказе других предметов. Удаление с предубеждением!

Примечание: remove_if чаще всего используется с erase, и оно сохранит порядок остальных элементов. Однако partition не заботится о порядке элементов и работает намного быстрее.

раздел-test.cpp:
make partition-test && echo 1 alien 9 alien 2 8 alien 4 7 alien 5 3 | ./partition-test

#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <vector>

using namespace std;

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &container) {
  bool comma = false;
  for (const auto &x : container) {
    if (comma)
      os << ", ";
    os << *x;
    comma = true;
  }
  return os;
}

int main() {
  vector<shared_ptr<string>> iv;
  auto x = make_shared<string>();
  while (cin >> *x) {
    iv.push_back(x);
    x = make_shared<string>();
  }
  cout << iv << '\n';

  iv.erase(partition(begin(iv), end(iv),
                     [](const auto &x) { return *x != "alien"s; }),
           end(iv));
  cout << iv << '\n';
  return 0;
}
...