Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

STL и указатель(

9.4K
07 февраля 2010 года
1_Aposym_1
68 / / 01.11.2007
InfoPoint, StateObject структуры
TBox класс
Код:
vector<InfoPoint>Point;
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//<---
Почему происходит потеря указателя или потеря данных?
41K
07 февраля 2010 года
gaga
44 / / 22.07.2009
Я в этой части ошибки не вижу. Твой код, слегка измененный, выдает то, что ожидается. Видимо, ошибка в выводе или в реализации одного из твоих классов.
Код:
gaga@gaga:~/delme$ cat ./test.cpp
#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
9.4K
07 февраля 2010 года
1_Aposym_1
68 / / 01.11.2007
Цитата: gaga
Я в этой части ошибки не вижу. Твой код, слегка измененный, выдает то, что ожидается. Видимо, ошибка в выводе или в реализации одного из твоих классов.
Код:
gaga@gaga:~/delme$ cat ./test.cpp
#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]; )то все работает. Скорее всего, вовремя расширения вектора происходят различные "преобразования".

43K
07 февраля 2010 года
loki231
76 / / 27.09.2009
При изменении размера вектора происходит что-то вроде realloc()'а. Поэтому адреса элементов могут измениться. Используйте вместо vector<> list<>, или сделайте Point.reserve(20), это сразу выделит память для 20 элементов.
9.4K
07 февраля 2010 года
1_Aposym_1
68 / / 01.11.2007
Цитата: loki231
При изменении размера вектора происходит что-то вроде realloc()'а. Поэтому адреса элементов могут измениться. Используйте вместо vector<> list<>, или сделайте Point.reserve(20), это сразу выделит память для 20 элементов.


Я в вектор кладу теперь указатели - так проще!
А такой вопросик. Дапустим есть вектор с n элементами, и хочу удалить какой-то, стоящий в середине, элемент, незная его ID в массиве. Это возможно?

43K
07 февраля 2010 года
loki231
76 / / 27.09.2009
Возможно. Почитайте, наконец, описание класса std::vector<>.
602
11 февраля 2010 года
KPI Student
265 / / 16.12.2006
Цитата: 1_Aposym_1
Я в вектор кладу теперь указатели - так проще!

Так не проще. Это называется "талисман из яиц девственника, +3 к удаче".

В любом случае при изменении количества элементов вектора итераторы (или указатели, или ссылки) на его элементы могут стать невалидными. А могут и не стать невалидными. Точнее, они то будут портиться, то нет -- в зависимости от фазы луны (тьфу, от политики изменения реального размера вектора).

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

602
11 февраля 2010 года
KPI Student
265 / / 16.12.2006
Цитата:
"талисман из яиц девственника, +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(...)

602
11 февраля 2010 года
KPI Student
265 / / 16.12.2006
Цитата: 1_Aposym_1
Я в вектор кладу теперь указатели - так проще!
А такой вопросик. Дапустим есть вектор с n элементами, и хочу удалить какой-то, стоящий в середине, элемент, незная его ID в массиве. Это возможно?



Все возможно.

Для удаления по известному итератору есть vector::erase(...). Далее читать мануал.

 
Код:
std::vector<int> a;
...
a.erase( std::find( ... ) );


Для удаления по известному значению есть std::remove(...). Из стандартных алгоритмов.
 
Код:
std::vector<std::string> a;
...
std::remove( a.begin(), a.end(), "aaa" );  // Читать мануал!!!


Для удаления по какому-то признаку есть даже std::remove_if
 
Код:
std::vector<Shape> a;
...
std::remove_if( a.begin(), a.end(), IsTriangle() ); // тоже чувствительная к чтению мануала
9.4K
14 февраля 2010 года
1_Aposym_1
68 / / 01.11.2007
Ясно, но все ровно любое удаление, сводиться к тому, что происходит внуренний цикл по элементам вектора, достается ID элемента, а дальшу удаление! теперь все ясно. Я думаю тему можно закрыть тему.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог