Указатель на элемент std::vector

у меня есть что-то вроде

struct functor
{
  functor(){}
  virtual int operator()()=0;
};

struct impl : public functor
{
  int i;
  impl(int ii) : i(ii) {}
  virtual int operator()(){return i;};
};

void call(functor& f) {std::cout << f() << std::endl;}
class holder
{
public:
  holder(){}
  std::vector<functor*> dps;
};

class veer
{
public:
  std::vector<holder> hs;
  std::vector<impl> ds;
  veer(){}
  void add_h(int i)
  {
    ds.push_back(impl(i));
    holder th;
    th.dps.push_back(&ds.back()); //here
    hs.push_back(th);
  }
};
int main()
{
  veer v;
  v.add_h(10);
  v.add_h(9);
  for (auto ih: v.hs)   
    for (auto ifn : ih.dps)
    call(*ifn);
  return 0;
}

Этот сегмент неисправен. Мне жаль, что я не могу сделать это проще, это самое простое и наиболее близкое к моему реальному коду, как я мог бы его сделать. Мне нужен вектор указателей на функциональные объекты. Я предполагаю, что в строке с пометкой //here я отправляю недопустимый указатель, но кроме этого я все еще пытаюсь понять это.


person noobermin    schedule 30.05.2014    source источник
comment
У вас есть потенциальная проблема, потому что вы не предоставляете виртуальный деструктор в functor. Если бы вы выполнили полиморфное удаление указателя impl через указатель functor, это было бы неопределенным поведением. Я не вижу, чтобы вы делали это в этом коде, но об этом нужно знать.   -  person Fred Larson    schedule 30.05.2014
comment
Ты прав. Спасибо за внимание.   -  person noobermin    schedule 30.05.2014


Ответы (1)


Проблема в том, что vector не гарантируется сохранение того же хранилища:

Если новый размер() больше, чем емкость(), то все итераторы и ссылки (включая итератор, прошедший конец) становятся недействительными. В противном случае только итератор, прошедший конец, становится недействительным.

Каждый раз, когда вы вызываете add_h, вы потенциально делаете недействительными все указатели, которые вы сохранили в своем std::vector<functor*>. Я не могу придумать вариант использования, чтобы иметь вектор вещей и вектор указателей на эти вещи в одном и том же порядке. Вы уверены, что это то, что вам нужно?

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

person Collin    schedule 30.05.2014
comment
Хуже того, код пытается удержать указатель на локальный (фактически временный) объект. - person Konrad Rudolph; 30.05.2014
comment
Правильно, я отношусь к ним как к старым массивам C. Это имеет большой смысл. Я глупо предполагаю, что он имеет фиксированную длину и не перераспределяет память. Я, вероятно, должен попытаться найти лучший способ вместо этой чепухи. - person noobermin; 30.05.2014
comment
@KonradRudolph &vec.back() не дает вам указатель на фактический вектор, поскольку он возвращает ссылку? Или есть что-то еще, чего я не замечаю? - person Collin; 30.05.2014
comment
@Коллин ds.back() не проблема, проблема ds.push_back(impl(i));. - person Konrad Rudolph; 30.05.2014
comment
@KonradRudolph veer::ds - это вектор реализации, хранящийся по значению. держатель::ds (теперь держатель::dps) — это вектор указателей на функторы (суперкласс impl). Я попытался получить адрес элемента veer::ds, который, я полагаю, был передан по значению в вектор veer::ds. Это неправильно? Да, я понимаю, что название неудачное, я могу это изменить. - person noobermin; 30.05.2014
comment
@noobermin О, я вижу, ds находится в той же области, что и hs. Тогда это не ошибка, но здесь все еще очень неясно право собственности, это, безусловно, кричит, чтобы кто-то совершил ошибку в будущем. Возможно, правильное именование помогло бы, но поскольку висячие ссылки легко являются источником ошибок сегментации № 1 в современном C++, я бы уделил некоторое внимание тому, чтобы сделать этот тип безопасным (чтобы висячая ссылка каким-то образом вызывала ошибку типа — не задумываясь об этом, я не могу сказать, как подойти к этому, хотя). - person Konrad Rudolph; 30.05.2014