Указатель на векторный элемент — В Windows

#c #pointers

#c #указатели

Вопрос:

У меня есть следующие классы:

 class A {};

class B { vector<A> vect; };
  

Я могу получить доступ к произвольному A следующим образом:

 A a = b.vect[0];
// A *a_ptr = amp;a;
  

Но как я могу напрямую перейти к *a_ptr?

 A *a_ptr = amp;b.vet[0];
  

компилируется и не выдает ошибок во время выполнения, но указывает на неправильное расположение в памяти.

Редактировать:

мой реальный пример:http://ideone.com/kP8NK

В то время как Ideone выдает ожидаемое « You are now at 0, 0, 0 «, компилятор MS VisualStudio выдает « You are now at 6624656, -33686019, -1414812757 «

Комментарии:

1. Что вы подразумеваете под «он указывает на неправильное местоположение в памяти»?, Кстати, делать это опасно, так как следующий push_back может сделать этот указатель недействительным.

2. получение значения a_ptr.Field дает мне неправильное значение, в то время как значение.Field является правильным

3. вам пришлось бы выполнить a_ptr -> Поле

4. @pistacchio: это невозможно, поскольку A a = b.vect[0] копирует объект из того же местоположения, откуда вы берете указатель.

5. почему вы не используете ссылки, это то, что в любом случае возвращает operator[] of vector.

Ответ №1:

Это не «неправильно», вы просто упустили разницу. А именно:

 A a = b.vect[0]; // Makes `a` a *copy* of the vector element
A *a_ptr = amp;a; // Address of the copy

A *a_ptr2 = amp;b.vect[0]; // Address of the element, not a copy
  

Чтобы получить эквивалентность, вы должны изменить свой первый на:

 Aamp; a = b.vect[0]; // Makes `a` a reference to the vector element
A *a_ptr = amp;a; // Address of the element, not a copy
  

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


Проблема в том, что std::vector<>::push_back это приведет к аннулированию ссылок, указателей и итераторов на элементы, когда size() == capacity() поскольку ему необходимо выделить новый фрагмент памяти. Использование недействительного указателя (и др.) приводит к неопределенному поведению, поэтому ваши результаты неизвестны.

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

Комментарии:

1. Я не думаю, что это имеет смысл, потому что vector возвращает ссылку, а не копию object

2. @Oleg: Да, он возвращает ссылку, но a это не ссылочный тип, это тип значения; поэтому для его инициализации создается копия (ссылки).

3. верно, но в чем разница между получением адреса из ссылки, возвращаемой методом, или инициализацией возвращаемым значением?

4. @Oleg: Они будут другими. (Однако теперь мы знаем, что у операционной системы возникли проблемы не с этой проблемой.)

Ответ №2:

A *a_ptr = amp;b.vect[0]; правильно. Если у вас это не работает, значит, вы делаете что-то другое или модифицируете вектор после получения указателя. Модификации вектора обычно делают недействительными все указатели и итераторы на его элементах.

Ответ №3:

У меня это работает (после изменения vet на vect ). Смотрите http://ideone.com/V3tGS для доказательства.

Комментарии:

1. class A { public: ... }; ? Фу. 🙂 struct A { ... }; .

2. это была опечатка, поскольку опубликованный пример является упрощением реального кода, который вы теперь можете увидеть при РЕДАКТИРОВАНИИ

3. @GMan: Я хотел внести как можно меньше изменений в код OP. В противном случае мы получаем ответный вопрос: «Почему вы изменили class на struct

Ответ №4:

Ваша проблема в том, что вы изменяете вектор после присвоения адреса указателю. Здесь:

  World w;
    w.worldMap.push_back(Room(0, 0, 0)); // starting point
    Room *starting_room = amp;w.worldMap[0];

    w.worldMap.push_back(Room(1, 1, 5)); // treasure room
    Room treasure_room = w.worldMap[1];
  

Изменение контейнера делает недействительными все указатели / ссылки.

Если вы удалите эти строки:

     w.worldMap.push_back(Room(1, 1, 5)); // treasure room
    Room treasure_room = w.worldMap[1];
  

Это работает идеально