Vector указателей
CNode* node=new CNode(X,Y);
nodes.push_back(node);
Я удаляю так:
for (vector<CNode*>::iterator i=nodes.end()-1;i>=nodes.begin();i--){
delete (*i);
nodes.erase(i);
}
В процессе выполнения вылетает ошибка
Как правильно освободить память?
А за пределами цикла написать nodes.clear();
nodes.erase() нужно бы убрать.
А за пределами цикла написать nodes.clear();
Допустим.А как удалить только один элемент из векторА?
Допустим.А как удалить только один элемент из векторА?
Один конечно через erase(), но сперва нужно с него "ступить". Что-то типа
for(vector<CNode*>::iterator i=nodes.end()-1;i>=nodes.begin();i--)
{
if(j!=nodes.end())
{
nodes.erase(j);
j = nodes.end();
}
if(удалить_тек_элемент==true)j = i;
}
if(j!=nodes.end())nodes.erase(j);
Один конечно через erase(), но сперва нужно с него "ступить". Что-то типа
for(vector<CNode*>::iterator i=nodes.end()-1;i>=nodes.begin();i--)
{
if(j!=nodes.end())
{
nodes.erase(j);
j = nodes.end();
}
if(удалить_тек_элемент==true)j = i;
}
if(j!=nodes.end())nodes.erase(j);
Спасибо, сейчас попробую
Если есть большой объект CNode, как лучше организовать программу:
vector<CNode*> nodes;
CNode* node=new CNode(X,Y);
nodes.push_back(node);
или
vector<CNode> nodes;
nodes.push_back(CNode(X,Y));
imho второй способ лучше.
В первом случае +4*n памяти, +дин.объекты, которых нужно потом отдельно удалять.
imho второй способ лучше.
Что такое n? Размер объекта?
Что такое n? Размер объекта?
Нет. Число объектов Nodes. Это лишние указатели.
Имеется вектор указателей на CNode
CNode* node=new CNode(X,Y);
nodes.push_back(node);
Я удаляю так:
for (vector<CNode*>::iterator i=nodes.end()-1;i>=nodes.begin();i--){
delete (*i);
nodes.erase(i);
}
В процессе выполнения вылетает ошибка
Как правильно освободить память?
Вообще, хорошим стилем программирования в данном случае использовать смартпоинтеры...
Вообще, хорошим стилем программирования в данном случае использовать смартпоинтеры...
Можно с этого момента поподробнее?
Теперь новый вопрос:
Мне надо из итератора получить указатель на объект. Я пробую так
for (vector<CNode>::iterator i=nodes.begin();i<nodes.end();i++){
if (i->HitTest(X,Y)==true){
BeginDrag(reinterpret_cast<CNode*>(&i));
return false;
}
}
Но в ф-ю BeginDrag передается какой-то мусор
void CNodes::BeginDrag(CNode* node){
node->Assign(5,5);
}
Как правильно сделать и в чем сдесь ошибка?
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(i);
return false;
}
}
void CNodes::BeginDrag(CNode* node)
{
node->Assign(5,5);
}
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(i);
return false;
}
}
void CNodes::BeginDrag(CNode* node)
{
node->Assign(5,5);
}
------ Build started: Project: First, Configuration: Debug Win32 ------
Compiling...
Node.cpp
c:\documents and settings\xxx\мои документы\visual studio 2005\projects\first\first\node.cpp(31) : error C2664: 'CNodes::BeginDrag' : cannot convert parameter 1 from 'std::_Vector_iterator<_Ty,_Alloc>' to 'CNode *'
with
[
_Ty=CNode,
_Alloc=std::allocator<CNode>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Build log was saved at "file://c:\Documents and Settings\XXX\Мои документы\Visual Studio 2005\Projects\First\First\Debug\BuildLog.htm"
First - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
------ Build started: Project: First,
<skipped>
Странно. У меня в VC6 компилируется без проблем. Тогда наверно нужно изменить заголовок BeginDrag
void CNodes::BeginDrag(vector<CNode>::iterator node)
Странно. У меня в VC6 компилируется без проблем. Тогда наверно нужно изменить заголовок BeginDrag
void CNodes::BeginDrag(vector<CNode>::iterator node)
Жаль
Жаль
На худой конец
BeginDrag(reinterpret_cast<CNode*>(i));
т.е. i без &.
На худой конец
BeginDrag(reinterpret_cast<CNode*>(i));
т.е. i без &.
А может все же просто так:
BeginDrag(&(*i));
для данного случая reinterpret_cast не требуется
Имеется вектор указателей на CNode
CNode* node=new CNode(X,Y);
nodes.push_back(node);
Я удаляю так:
for (vector<CNode*>::iterator i=nodes.end()-1;i>=nodes.begin();i--){
delete (*i);
nodes.erase(i);
}
В процессе выполнения вылетает ошибка
Как правильно освободить память?
Во первых, при вызове erase итератор становится не действительниым, поэтому его использовать нельзя. Кстати все итераторы указывавшие на этот вектор становятся не действительными. Для этих целей метод erase возвращает новый итератор.
код цикла надо переписать так:
vector<CNode*>::iterator iter = nodes.begin();
while ( iter != nodes.end() )
{
delete *iter;
iter = nodes.erase(iter);
}
во вторых, ты в коде пытался удалить nodes.end() чего делать мягко говоря не желательно.
Во вторых всегда используй с итераторами префиксную форму вместо постфиксной, т.е. ++i вместо i++, т.к. не тратится время на создание предыдущей копии итератора.
Далее, насчёт выбора vector<CNode> и vector<CNode*>. Выбор должен исходить из того, насколько быстро выполняется копирование объекта Node. т.е.
CNode n1, n2;
n1 = n2; - эсли эта операция затратна, то следует предпочесть список указателей, т.к. в STL операция копирования наиболее часто используемая.
Насчёт умных указателей.
используй объект shared_ptr<T> из библиотеки boost, библиотеку можешь взять на сайте boost.org.
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(&(*i)); - вот здесь поправил
return false;
}
}
void CNodes::BeginDrag(CNode* node)
{
node->Assign(5,5);
}
for(vector<CNode>::iterator i=nodes.begin();i!=nodes.end();i++)
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(&(*i)); - вот здесь поправил
return false;
}
}
void CNodes::BeginDrag(CNode* node)
{
node->Assign(5,5);
}
А собственно, чем вам не нравится использовать
{
if(nodes->HitTest(X,Y))
{
BeginDrag(nodes);
return false;
}
}
А собственно, чем вам не нравится использовать
{
if(nodes->HitTest(X,Y))
{
BeginDrag(nodes);
return false;
}
}
Всем нравится, просто обсуждение было в нотации итераторов.
А так если использование вектора оправдано, и не будет изменено в дальнейшем ни на что другое, то без проблем.
Тут можно полемику долго развивать, например for_each предложить, но я думаю остоновимся просто на работающем варианте
{
if(nodes->HitTest(X,Y))
{
BeginDrag(nodes);
return false;
}
}
Я так вчера и сделал.Все работает ОК.Но чисто из теоретических интересов не пойму почем не работает мой вариант.
BeginDrag(&(*i)); - по-моему это извращение.Правда не проверял насчет работы.Почему тогда не работает просто BeginDrag(i) или в паре с reinterpret_cast?
BeginDrag(&(*i)); - по-моему это извращение.Правда не проверял насчет работы.Почему тогда не работает просто BeginDrag(i) или в паре с reinterpret_cast?
Сделай параметр в BeginDrag не указателем, а ссылкой, и тогда будет запись BeginDrag(i);
Сделай параметр в BeginDrag не указателем, а ссылкой, и тогда будет запись BeginDrag(i);
Интересно это как же,так что ли:
void CNodes::BeginDrag(CNode& node)
{
node.Assign(5,5);
}
for(vector<CNode>::iterator i=nodes.begin();i!=nodes.end();i++)
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(i);//Ошибка!!!
return false;
}
}
И это по твоему должно работать?!!
И еще
BeginDrag(&(*i)); - по-моему это извращение.Правда не проверял насчет работы.
Вот именно сначала проверь. Вообще то это самый правильный вариант для данного случая а не какое не извращение,если ты не умееш с итераторами обращяться то это не их вина.
Может лучше почитаеш немного Страуструпа.
К примеру:
class C{
...
int var;
};
vector<C> vc;
vector<C>::iterator it;
теперь мы можем обращяться из итератора к переменной var так:
it->var=0;
int i = it->var;
или
(*it).var=0;
int i = (*it).var;
Теперь что касается * и -> это идут операторы разыменовывания итератора т.е. получение реального объекта на что указывает итератор в данный момент. т.е. в данном случае *it эквивалентно как если бы мы просто имели переменную типа (C mv) mv есть *it,и соответсвенно поэтому в твоем случае мы использовали конструкцию &(*it) что эквивалентно в случае с обычной переменной &mv.
Надеюсь хоть что то понятно,за остальным хотя бы к страуструпу.
Интересно это как же,так что ли:
void CNodes::BeginDrag(CNode& node)
{
node.Assign(5,5);
}
for(vector<CNode>::iterator i=nodes.begin();i!=nodes.end();i++)
{
if (i->HitTest(X,Y)==true)
{
BeginDrag(i);//Ошибка!!!
return false;
}
}
И это по твоему должно работать?!!
Вобще то вызов должен быть такой BeginDrag(*i);
т.к. сначала надо разыменовать указатель, это и имелось ввиду. Следующий раз буду свои слова дополнять кодом, просто думал и так будет всё понятно.
Вот именно сначала проверь. Вообще то это самый правильный вариант для данного случая а не какое не извращение,если ты не умееш с итераторами обращяться то это не их вина.
Может лучше почитаеш немного Страуструпа.
А это всё к чему или кому адресовывалось?
Уважаемый vitaly2003s,давай только не будем отсылать к Страустрапу, по-моему форумы существуют для того, чтоб учиться, а не для того, чтоб умничать, не посоветовав ничего путнего.
Ну еслидаже непонятно было что я описал про разыменование о чем ты даже и не подозревал,то страуструп тут бессилен.
Ну еслидаже непонятно было что я описал про разыменование о чем ты даже и не подозревал,то страуструп тут бессилен.
BeginDrag(&(*i));
Это ты называешь разыменованием?Это то же самое, что a+1-1+2-2,в смысле, две противоположные операции, и не надо говорить, о чем я подозревал, а о чем нет.Тем более, что твой вариант не подошел
BeginDrag(&(*i));
Это ты называешь разыменованием?Это то же самое, что a+1-1+2-2,в смысле, две противоположные операции, и не надо говорить, о чем я подозревал, а о чем нет.Тем более, что твой вариант не подошел
Это не тоже самое.
Смотрим по шагам.
i - имеет тип vector<CNode>::iterator.
это итератор, это не указатель в общем смысле, хотя многие реализации вектора для DEBUG и все для RELEASE реализуют это как указатель. Но в любом случае это итератор.
*i - операция разъименовывания итератора, т.е. имеет тип CNode.
Твоя функция хочет тип CNode*, поэтому нужно получить адрес объекта,
т.е. &(*i).
как видим i имеет тип vector<CNode>::iterator
а &(*i) имеет тип CNode*.
В общем случае это разные вещи.