STL и указатель(
TBox класс
InfoPoint *T_Point;
bool t = true;
for(int i = 0; i < 10; i++)
Point.push_back(InfoPoint(new StateObject(), new TBox(),10,t));
T_Point = &Point[5];
for(int i = 0; i < 10; i++)
Point.push_back(InfoPoint(new StateObject(), new TBox(),10,t));
for(int i = 0; i < 20; i++)
CL.Cout(Point.R);
CL.Cout(T_Point->R);
вот результат
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
10.000000
0.000000//<---
Почему происходит потеря указателя или потеря данных?
#include<vector>
#include<iostream>
using namespace std;
struct InfoPoint {
double R;
double Phi;
bool isVisible;
InfoPoint( double r, double phi, bool visible ) : R(r), Phi(phi), isVisible(visible) {}
};
int main() {
vector<InfoPoint>Point;
InfoPoint *T_Point;
bool t = true;
for(int i = 0; i < 10; i++) {
Point.push_back(InfoPoint(123.456, 2.678, t));
}
T_Point = &Point[5];
for(int i = 0; i < 10; i++) {
Point.push_back(InfoPoint(98.43, 78.467, t));
}
for(int i = 0; i < 20; i++) {
cout << Point.R << endl;
}
cout << "---" << endl << T_Point->R << endl;
return 0;
}
gaga@gaga:~/delme$ g++ test.cpp -o test && ./test
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
---
123.456
#include<vector>
#include<iostream>
using namespace std;
struct InfoPoint {
double R;
double Phi;
bool isVisible;
InfoPoint( double r, double phi, bool visible ) : R(r), Phi(phi), isVisible(visible) {}
};
int main() {
vector<InfoPoint>Point;
InfoPoint *T_Point;
bool t = true;
for(int i = 0; i < 10; i++) {
Point.push_back(InfoPoint(123.456, 2.678, t));
}
T_Point = &Point[5];
for(int i = 0; i < 10; i++) {
Point.push_back(InfoPoint(98.43, 78.467, t));
}
for(int i = 0; i < 20; i++) {
cout << Point.R << endl;
}
cout << "---" << endl << T_Point->R << endl;
return 0;
}
gaga@gaga:~/delme$ g++ test.cpp -o test && ./test
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
123.456
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
98.43
---
123.456
Я выложил проект с этим куском кода. Глянь, но ошибка осталась.
Когда я в вектор кладу( Point.push_back(new InfoPoint(....)) ) указатель и от туда беру его ( T_Point = Point[5]; )то все работает. Скорее всего, вовремя расширения вектора происходят различные "преобразования".
Я в вектор кладу теперь указатели - так проще!
А такой вопросик. Дапустим есть вектор с n элементами, и хочу удалить какой-то, стоящий в середине, элемент, незная его ID в массиве. Это возможно?
Так не проще. Это называется "талисман из яиц девственника, +3 к удаче".
В любом случае при изменении количества элементов вектора итераторы (или указатели, или ссылки) на его элементы могут стать невалидными. А могут и не стать невалидными. Точнее, они то будут портиться, то нет -- в зависимости от фазы луны (тьфу, от политики изменения реального размера вектора).
Поэтому если перед вами стоит задача написать программу, которая не будет иногда падать по неясной причине в зависимости от случайных обстоятельств, или что хуже, работать, не но правильно -- никогда не используйте повторно итераторы (указатели, ссылки) после изменения количества элементов в векторе.
Объясняю почему:
Что такое вектор? Это непрерывный буфер (массив) в котором хранятся данные.
Можно ли изменить размер непрерывного буфера данных? Нет, нельзя.
Можно только удалить старый буфер и выделить новый.
Как происходить добавление элемента в вектор в простейшем случае?
Выделяем новый буфер размером на один элемент больше старого, копирует туда содержимое старого, записываем в конец один новый.
Как видите, самый простой случай очень медленный - в этом случае для добавления 1005003-го элемента надо скопировать предыдущие 1005002 в новый буфер. Это ужасно медленно. Поэтому придумана следующая оптимизация:
В зависимости от религиозных или иных убеждений разработчиков определенной версии STL, выбираются какие-то "граничные" размеры вектора, например "4, 16, 32, 256, 1024, ...". Далее когда вы создаете пустой вектор в нем сразу выделяется буфер на 4 элемента. При этом, к примеру, size() = 0, capacity()=4. Далее при добавлении 4 элементов по одному ничего не выделяется, просто увеличивается size() и ничего не выделяется заново.
Далее вы добавляете 5й элемент - при этом выделяется новый буфер (размером элементов на 16), туда копируются 4 существующих элемента, добавляется один пятый.
Другими словами, что происходит у вас:
В какой-то момент вы берете указатель на пятый элемент в буфере вектора. Потом вы добавляете туда еще десяток элементов. При этом может быть создан (а может быть и не создан) новый буфер большего размера. В случае создания большего буфера старый будет удален за ненадобностью. Следовательно, указатель, котороый указывает на элемент номер 5 в старом буфере будет указывать неизвестно на что. В общем (в случае использования амулета из яиц девственника) вам может быть и повезет, и там окажутся старые данные, похожие на правду. А может и не повезет - и во время разыменования вы получите что-то непонятное.
Суть сказанного: указатели, итераторы, и ссылки, полученные до изменения количества элементов в векторе, будь то добавление или удаление, нужно считать невалидными после изменения его размера.
То есть ваш T_Point = &Point[5]; нельзя использовать после Point.push_back(...)
А такой вопросик. Дапустим есть вектор с n элементами, и хочу удалить какой-то, стоящий в середине, элемент, незная его ID в массиве. Это возможно?
Все возможно.
Для удаления по известному итератору есть vector::erase(...). Далее читать мануал.
...
a.erase( std::find( ... ) );
Для удаления по известному значению есть std::remove(...). Из стандартных алгоритмов.
...
std::remove( a.begin(), a.end(), "aaa" ); // Читать мануал!!!
Для удаления по какому-то признаку есть даже std::remove_if
...
std::remove_if( a.begin(), a.end(), IsTriangle() ); // тоже чувствительная к чтению мануала