Russian Qt Forum

Программирование => С/C++ => Тема начата: Даниил от Март 13, 2012, 14:06



Название: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 14:06
Приветствую всех.
Появилась внезапная трабла - хочу запихать в вектор свой класс. Только вот незадача, как только я push_back'аю объект в вектор, тот вызывает деструктор, при чем имеется какая-то странная зависимость от количества "запинаных" объектов, посмотрите, подскажите - где тут засада.
Код
C++ (Qt)
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
 
class Coord
{
private:
   int x, y;
public:
   Coord(){x = 0; y = 0;}
   Coord(int _x, int _y){x = _x; y = _y;}
   Coord(const Coord &c){x = c.x;}
   ~Coord(){cout << "Delete Coord[" << x << ',' << y << "]" << endl;}
   Coord &operator=(const Coord &c);
   bool operator <(const Coord &c) const;
   friend ostream &operator <<(ostream& s, const Coord &c);
};
 
Coord &Coord::operator =(const Coord &c)
{
   if(this == &c)return *this;
   else
   {
       this->x = c.x;
       this->y = c.y;
       return *this;
   }
}
 
bool Coord::operator <(const Coord &c)const
{
   if(this->x < c.x)return true;
   else if(this->x == c.x)
   {
       if(this->y < c.y)return true;
   }
   return false;
}
 
ostream &operator <<(ostream& s, const Coord &c)
{
   cout << "Coord[" << c.x << "," << c.y << "]" << endl;
   return s;
}
 
int main()
{
   vector<Coord> v;
   v.push_back(Coord());
   v.push_back(Coord());
   v.push_back(Coord());
   cout << v[0];
   cout << v[1];
   cout << v[2];
 
   getchar();
   return 0;
}
 
Вывод:
Код:
Delete Coord[0,0]
Delete Coord[0,11665604]
Delete Coord[0,0]
Delete Coord[0,11665604]
Delete Coord[0,825111086]
Delete Coord[0,0]
Coord[0,11669608]
Coord[0,2037603443]
Coord[0,1127952947]


Название: Re: Преждевременный вызов деструктора
Отправлено: Пантер от Март 13, 2012, 14:09
Все правильно - вектор хранит копию объекта. При изменении вектора происходит перераспределение объектов копированием.


Название: Re: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 14:25
м-м-м, поставлю вопрос конкретней - что нужно сделать, чтобы можно было в векторе хранить самописные объекты.


Название: Re: Преждевременный вызов деструктора
Отправлено: mutineer от Март 13, 2012, 14:27
м-м-м, поставлю вопрос конкретней - что нужно сделать, чтобы можно было в векторе хранить самописные объекты.

Они уже сейчас там хранятся. В чем проблема-то?


Название: Re: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 14:29
Ну, вобще проблема есть - т.к. там хранится не то, что туда запихивали:
Код:
Coord[0,11669608]
Coord[0,2037603443]
Coord[0,1127952947]


Название: Re: Преждевременный вызов деструктора
Отправлено: ddrtn от Март 13, 2012, 14:31
Это потому, что у Вас неправильно определен конструктор копирования.  в нем копируется только х


Название: Re: Преждевременный вызов деструктора
Отправлено: mutineer от Март 13, 2012, 14:32
Ну, вобще проблема есть - т.к. там хранится не то, что туда запихивали:
Код:
Coord[0,11669608]
Coord[0,2037603443]
Coord[0,1127952947]

Вектор копирует объекты. Причем не один раз (при перераспределении памяти)
А у тебя неполный конструктор копирования
Код
C++ (Qt)
Coord(const Coord &c){x = c.x;}


Название: Re: Преждевременный вызов деструктора
Отправлено: Пантер от Март 13, 2012, 14:32
Coord(const Coord &c){x = c.x;} - а y игноришь, вот и получаешь мусор.


Название: Re: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 14:35
Спасибо. Прозрел. :P


Название: Re: Преждевременный вызов деструктора
Отправлено: Пантер от Март 13, 2012, 14:38
В данном случае свой копирующий конструктор и опрератор присваивания не нужны, так как класс тривиален.


Название: Re: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 17:43
Да я класс обрезал, чтобы сюда не кидать 300 строк кода, а так да, только в теории нужно еще оператор == перегрузить, а то вектор может начать ругаться.


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 13, 2012, 17:55
Конструктор лучше оформить так
Код
C++ (Qt)
Coord( int _x = 0, int _y = 0 )  { x = _x; y = _y; }
 
Тогда он годится и по умолчанию

А оператор < написать проще, (а то у Вас голову можно сломать)

Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   if (x < c.x) return true;
   if (x > c.x) return false;
   return y < c.y;
}
 
Оператор == вектору не требуется, но в такого класса нужен все равно


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 13, 2012, 18:40
Конструктор лучше оформить так
Код
C++ (Qt)
Coord( int _x = 0, int _y = 0 )  { x = _x; y = _y; }
 
Тогда он годится и по умолчанию

А оператор < написать проще, (а то у Вас голову можно сломать)

Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   if (x < c.x) return true;
   if (x > c.x) return false;
   return y < c.y;
}
 
Оператор == вектору не требуется, но в такого класса нужен все равно


А оператор < вообще бредово определять для данного класса)
Какая точка будет больше p1(10, 1) или p2(1, 10) ?

Согласно вашей реализации p1 окажется больше.. Но с чего это вы нарушаете равноправие между x и y компонентами?
И как конечный пользователь должен досмысливать поведение такого оператора для объекта точки? Это не логично.


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 13, 2012, 18:44
Да и ещё:
Обычно так не пишут:
Код
C++ (Qt)
Coord &Coord::operator =(const Coord &c)
{
   if(this == &c)return *this;
   else
   {
       this->x = c.x;
       this->y = c.y;
       return *this;
   }
}
 

Лучше так:
Код
C++ (Qt)
Coord &Coord::operator =(const Coord &c)
{
   if (this != &c)
   {
       x = c.x;
       y = c.y;
   }
   return *this;
}
 


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 13, 2012, 18:58
А оператор < вообще бредово определять для данного класса)
Какая точка будет больше p1(10, 1) или p2(1, 10) ?

Согласно вашей реализации p1 окажется больше.. Но с чего это вы нарушаете равноправие между x и y компонентами?
И как конечный пользователь должен досмысливать поведение такого оператора для объекта точки? Это не логично.
Не всегда концептуальность идет в такт с конкретикой/реализацией. Есть вектор точек, надо удалить повторяющиеся. Что будете делать без оператора < ? Или у Вас есть др. предложения как его определить? Так что потише там с "бредово" и.т.п.  :)



Название: Re: Преждевременный вызов деструктора
Отправлено: Даниил от Март 13, 2012, 19:02
 :o Да я просто так обозвал класс - прекратите холивар!


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 13, 2012, 19:47
:o Да я просто так обозвал класс - прекратите холивар!

Да какой ещё холивар) Выпейте лучше стакан холодной воды)

А оператор < вообще бредово определять для данного класса)
Какая точка будет больше p1(10, 1) или p2(1, 10) ?

Согласно вашей реализации p1 окажется больше.. Но с чего это вы нарушаете равноправие между x и y компонентами?
И как конечный пользователь должен досмысливать поведение такого оператора для объекта точки? Это не логично.
Не всегда концептуальность идет в такт с конкретикой/реализацией. Есть вектор точек, надо удалить повторяющиеся. Что будете делать без оператора < ? Или у Вас есть др. предложения как его определить? Так что потише там с "бредово" и.т.п.  :)



Тогда у меня вопрос: пусть есть вектор объектов (пусть просто обычных чисел), у которых нет оператора <, но есть операторы (=! ==)  Можно ли выкинуть из вектора повторяющиеся элементы?

И как Вам поможет определённый выше оператор < ?


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 13, 2012, 20:14
Тогда у меня вопрос: пусть есть вектор объектов (пусть просто обычных чисел), у которых нет оператора <, но есть операторы (=! ==)  Можно ли выкинуть из вектора повторяющиеся элементы?

И как Вам поможет определённый выше оператор < ?
Поможет так что я могу спокойно вызывать std::sort, помещать в std::set/map и делать многое другое без всяких усилий. А без оператора < мне придется поизвращаться: писать функторы. или городить хеш или юзать С-шный qsort - все это гораздо менее удобно. Поэтому нет оснований избегать оператора < только на том веском основании что он, дескать, "недостаточно идейный"  :)


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 13, 2012, 20:20
Тогда зачем его так усложнять?
Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   if (x < c.x) return true;
   if (x > c.x) return false;
   return y < c.y;
}
 

можно сделать проще:
Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   return x + y < c.x + c.y;    // или перемножать координаты или складывать и брать корень квадратный или ... :)
}
 


Название: Re: Преждевременный вызов деструктора
Отправлено: mutineer от Март 13, 2012, 20:59
Тогда у меня вопрос: пусть есть вектор объектов (пусть просто обычных чисел), у которых нет оператора <, но есть операторы (=! ==)  Можно ли выкинуть из вектора повторяющиеся элементы?

И как Вам поможет определённый выше оператор < ?

оператор < более универсален - с его помощь можно сортировать, сравнивать, а так же проверять на равенство. А вот с помощью операторов сравнения только проверять на равенство

Ну если в этих операторах нет странной логики, конечно:)


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 14, 2012, 00:47
Тогда у меня вопрос: пусть есть вектор объектов (пусть просто обычных чисел), у которых нет оператора <, но есть операторы (=! ==)  Можно ли выкинуть из вектора повторяющиеся элементы?

И как Вам поможет определённый выше оператор < ?
Поможет так что я могу спокойно вызывать std::sort, помещать в std::set/map и делать многое другое без всяких усилий. А без оператора < мне придется поизвращаться: писать функторы. или городить хеш или юзать С-шный qsort - все это гораздо менее удобно. Поэтому нет оснований избегать оператора < только на том веском основании что он, дескать, "недостаточно идейный"  :)

Я бы сделал как-то так:
Код
C++ (Qt)
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
 
template <class InputIterator, class T>
bool isContains(InputIterator begin, InputIterator end, const T& value)
{
   if (begin == end)
       return (*begin == value);
 
   for (InputIterator it = begin; it != end; ++it) {
       if (*it == value) return true;
   }
   return (*end == value);
}
 
// my_unique - шаблонная функция которая копирует из одного контейнера в другой
// только уникальные элементы
//
template <class InputIterator, class OutputIterator>
OutputIterator my_unique(InputIterator first, InputIterator last,
                              OutputIterator result )
{
   *result=*first;
   OutputIterator begin = result;
   while (++first != last) {
       if (!isContains(begin, result, *first))
         *(++result) = *first;
   }
   return ++result;
}
 
 
using namespace std;
 
int main()
{
   int arr[] = {0,0,1,0,2,9,3,0,0,7,4,5,6,0,7,8,9,0,0};
   const int size = sizeof(arr)/sizeof(arr[0]);
 
   vector<int> v(size);
   vector<int>::iterator it;
 
   it = my_unique(arr, arr+size, v.begin());
   v.resize(it - v.begin());
 
   copy(v.begin(), v.end(), ostream_iterator<int>(cout," "));
 
   return 0;
}
 
 
Вывод
Код
Bash
0 1 2 9 3 7 4 5 6 8
 

Теперь если заменить int на Point у которого есть оператор == то всё получится)


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 14, 2012, 01:11
Тогда у меня вопрос: пусть есть вектор объектов (пусть просто обычных чисел), у которых нет оператора <, но есть операторы (=! ==)  Можно ли выкинуть из вектора повторяющиеся элементы?

И как Вам поможет определённый выше оператор < ?

оператор < более универсален - с его помощь можно сортировать, сравнивать, а так же проверять на равенство. А вот с помощью операторов сравнения только проверять на равенство

Ну если в этих операторах нет странной логики, конечно:)
Ясненько)
И как Вы предлагаете сравнивать такие объекты, как вектора? И что значит отсортировать вектора?
Имхо, конечно, но это бред)


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 12:29
можно сделать проще:
Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   return x + y < c.x + c.y;    // или перемножать координаты или складывать и брать корень квадратный или ... :)
}
 
Ну тогда и оператор == должен быть в масть
Код
C++ (Qt)
bool Coord::operator == ( const Coord & c ) const
{
   return x + y == c.x + c.y;    
}
 
Хмм...  :)

Код
C++ (Qt)
return (*end == value);
 
Никто не обещал что end можно разыменовывать

Теперь если заменить int на Point у которого есть оператор == то всё получится)
Вы явно превзошли др фанов STL. У них ракообразные конструкции хоть экономят пару строчек (иногда). У Вас наоборот, увеличивают, + вкупе с линейным перебором. Видимо, это неважно, главное - побольше template, итераторов и вообще - полной абстракции. :)


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 13:17
Ну тогда и оператор == должен быть в масть
Почему? Операторы == и != можно определить и они будут отражать физическую и математическую суть такого сравнения, чего нельзя сказать о операторах < и >. Вот последние можно определять как захочется, мой вариант просто более оптимизированный чем твой.


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 13:39
Почему? Операторы == и != можно определить и они будут отражать физическую и математическую суть такого сравнения, чего нельзя сказать о операторах < и >. Вот последние можно определять как захочется, мой вариант просто более оптимизированный чем твой.
Тогда выходит так
Код
C++ (Qt)
a < b (false)
b < a (false)
a == b (false) Оба-на!
 
Хотя формально не ошибка - как этим пользоваться?  :)
Видимо не стоит так уж гнаться за "сутью", проще понимать < как некоторое "отношение" которое может использоваться для упорядочивания


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 13:43
Видимо не стоит так уж гнаться за "сутью", проще понимать < как некоторое "отношение" которое может использоваться для упорядочивания
Вот правильно.
Тогда повторю вопрос: Для чего у тебя такая сложная логика в этом операторе (по сравнению с моим вариантом)?


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 14:12
Тогда повторю вопрос: Для чего у тебя такая сложная логика в этом операторе (по сравнению с моим вариантом)?
В Вашем варианте в сортированном массиве возможен такой порядок

(-1, 1)
(-2, 2)
(-1, 1)


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 14:13
В Вашем варианте в сортированном массиве возможен такой порядок

(-1, 1)
(-2, 2)
(-1, 1)

Да и что?


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 14, 2012, 14:20
можно сделать проще:
Код
C++ (Qt)
bool Coord::operator < ( const Coord & c ) const
{
   return x + y < c.x + c.y;    // или перемножать координаты или складывать и брать корень квадратный или ... :)
}
 
Ну тогда и оператор == должен быть в масть
Код
C++ (Qt)
bool Coord::operator == ( const Coord & c ) const
{
   return x + y == c.x + c.y;    
}
 
Хмм...  :)

Код
C++ (Qt)
return (*end == value);
 
Никто не обещал что end можно разыменовывать

Теперь если заменить int на Point у которого есть оператор == то всё получится)
Вы явно превзошли др фанов STL. У них ракообразные конструкции хоть экономят пару строчек (иногда). У Вас наоборот, увеличивают, + вкупе с линейным перебором. Видимо, это неважно, главное - побольше template, итераторов и вообще - полной абстракции. :)


Оператор == для такого объекта, как точка логично определить так:
Код
C++ (Qt)
inline bool operator==(const Point &p1, const Point &p2)
{
   return ((p1.xp == p2.xp) && (p1.yp == p2.yp)) ? true : false;
   // или так:
   /*
   return (norm(p1-p2) <= epsilon);
   norm = x^2+y^2
  */

}
 

Цитировать
Код
C++ (Qt)
return (*end == value);
 
Никто не обещал что end можно разыменовывать
Не понял, почему это его нельзя разыменовывать?


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 14:25
Да и что?
Это не то что ожидается при нормальном операторе == (x == c.x && y == c.y). Напр удалить повторы из такого сортированного массива мы не сможем


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 14:27
Наверное, еще лучше так: :)
Код
C++ (Qt)
inline bool operator==(const Point &p1, const Point &p2)
{
   return (p1.xp == p2.xp) && (p1.yp == p2.yp);
}
 


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 14:29
Напр удалить повторы из такого сортированного массива мы не сможем
Почему?  ;D
Какое отношение имеет оператор < к операции удаления повторов?


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 14, 2012, 14:31
Наверное, еще лучше так: :)
Код
C++ (Qt)
inline bool operator==(const Point &p1, const Point &p2)
{
   return (p1.xp == p2.xp) && (p1.yp == p2.yp);
}
 


 ;D


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 14:37
Код:
    // или так:
    /*
    return (norm(p1-p2) <= epsilon);
    norm = x^2+y^2
   */
}
А вот так нельзя потому что нетранзитивно. За это я получал по дюнделю, и вынужден признать: MSVC говорит что такая сортировка некорректна

Не понял, почему это его нельзя разыменовывать?
end - итератор на элемент которого может и не быть. А если у Вас end нечто другое - тем хуже для Вас, такую стойкую ассоциацию менять не нужно


Название: Re: Преждевременный вызов деструктора
Отправлено: m_ax от Март 14, 2012, 14:43
Код:
    // или так:
    /*
    return (norm(p1-p2) <= epsilon);
    norm = x^2+y^2
   */
}
А вот так нельзя потому что нетранзитивно. За это я получал по дюнделю, и вынужден признать: MSVC говорит что такая сортировка некорректна

Не понял, почему это его нельзя разыменовывать?
end - итератор на элемент которого может и не быть. А если у Вас end нечто другое - тем хуже для Вас, такую стойкую ассоциацию менять не нужно

Да, транзитивность нарушается, но это не трагедия. (Во всяком случае, если не водить ещё и операторы < >)

end - итератор на элемент который в данной реализации всегда есть. (end это фактически result)
Код
C++ (Qt)
*result=*first;
   OutputIterator begin = result;
   while (++first != last) {
       if (!isContains(begin, result, *first)) // end будет равен result
         *(++result) = *first;
   }
   return ++result;
 


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 15:02
Почему?  ;D
Какое отношение имеет оператор < к операции удаления повторов?
Во многих случаях мы рассчитываем что в сортированном массиве одинаковые элементы (для которых == вернет true) идут подряд. Зачем же определять такой < при котором это не так?

Что-то Вы уж очень издалека заходите  :)


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 15:05
Во многих случаях мы рассчитываем что в сортированном массиве одинаковые элементы (для которых == вернет true) идут подряд. Зачем же определять такой < при котором это не так?
А разве при использовании моего оператора < для сортировки, это условие
Цитировать
одинаковые элементы (для которых == вернет true) идут подряд
не будет выполняться?


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 15:15
Нет, оператор == сортировке до лампочки


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 15:31
Нет, оператор == сортировке до лампочки
Эээ, а при использовании твоего оператора это измениться?


Название: Re: Преждевременный вызов деструктора
Отправлено: Igors от Март 14, 2012, 15:37
Эээ, а при использовании твоего оператора это измениться?
Да, он в масть с == типа (a < b == c < d). Давайте с этим закругляться, неудобно занимать так много места


Название: Re: Преждевременный вызов деструктора
Отправлено: BRE от Март 14, 2012, 15:45
Да, он в масть с == типа (a < b == c < d). Давайте с этим закругляться, неудобно занимать так много места
Ну раз в масть, то конечно, жаль математика об этом ничего не знает.