Russian Qt Forum

Разное => Говорилка => Тема начата: frostyland от Январь 07, 2011, 17:02



Название: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Январь 07, 2011, 17:02
Код
C++ (Qt)
void qDeleteAll ( ForwardIterator begin, ForwardIterator end )
void qDeleteAll ( const Container & c )
Deletes all the items in the range [begin, end) using the C++ delete operator. The item type must be a pointer type ...
И примером:
Код
C++ (Qt)
QList<Employee *> list;
list.append(new Employee("Blackpool", "Stephen"));
list.append(new Employee("Twist", "Oliver"));
 
qDeleteAll(list.begin(), list.end());
list.clear();

Зачем нужен метод, чистящий память, но оставляющий в контейнере невалидные указатели?
Это абсолютно глупо! Нет ни одного случая, где бы эти указатели-хвосты могли бы понадобиться.
.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
Все равно приходится либо помнить об его вызове, либо писать свою над-функцию...
Совершенно непонятна такая стратегия  ???



Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: lit-uriy от Январь 07, 2011, 17:30
>>.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
вот это точно глупость. У меня списке что? А в списке у меня список указателей на объекты, которые где-либо я использую. Если мне нужно очистить список, то это не значит, что мне нужно прибить эти объекты.



Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Январь 07, 2011, 17:31
А как ты представляешь себе вызов clear() внутри qDeleteAll?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Январь 07, 2011, 17:33
2 lit-uriy: Как понял, автор имел ввиду вызов clear() внутри qDeleteAll


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: lit-uriy от Январь 07, 2011, 17:36
>> Как понял, автор имел ввиду вызов clear() внутри qDeleteAll
 ну так вполне реально было бы реализовать для void qDeleteAll ( const Container & c )
т.к. контейнер известен:
Код
C++ (Qt)
void qDeleteAll ( const Container & c )
{
   ...
 
   c.clear();
}


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: brankovic от Январь 07, 2011, 17:50
Зачем нужен метод, чистящий память, но оставляющий в контейнере невалидные указатели?

Чтобы не очищать сам контейнер, конечно:

Код
C++ (Qt)
Vector <Data*> v;
v.resize (0, 99);
for (int j = 0; j < 77; ++j)
{
 for (int i = 0; i < 99; ++i)
   v [i] = new Data (i, j);
 
 ... //using v
 
 qDeleteAll (v);
}


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: ufna от Январь 07, 2011, 17:56
Контейнер - это контейнер, а данные - это данные. Удаление данных это одно, очистка контейнера - другое, и не стоит имхо в любом из вариантов "удалить и то и то".


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Январь 07, 2011, 19:29
>> Как понял, автор имел ввиду вызов clear() внутри qDeleteAll
 ну так вполне реально было бы реализовать для void qDeleteAll ( const Container & c )
т.к. контейнер известен:
Код
C++ (Qt)
void qDeleteAll ( const Container & c )
{
   ...
 
   c.clear();
}
Метод clear не const. Реализовать конечно реально, но не по уму. Метод/ф-ция должна делать то о чем их просили - и ничего больше. Много раз видел такое
Код
C++ (Qt)
#define DELETE_PTR(p)  (delete(p); p = NULL;)
 
Но не пытался критиковать delete  :)


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Январь 08, 2011, 05:19
> Метод clear не const.

+1


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: SABROG от Январь 08, 2011, 10:46
Я иногда храню в контейнерах QSharedPointer'ы вместо оригинального указателя и мне достаточно метода clear() у контейнера для одновременной очистки и освобождения памяти.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: lit-uriy от Январь 08, 2011, 11:34
>>Метод clear не const.
ну это сейчас не const. А если совершенствовать функцию qDeleteAll, то можно и убрать в ней это ограничение.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Январь 26, 2011, 13:54
>>.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
вот это точно глупость. У меня списке что? А в списке у меня список указателей на объекты, которые где-либо я использую. Если мне нужно очистить список, то это не значит, что мне нужно прибить эти объекты.
Долго гулял )))

>> Если мне нужно очистить список, то это не значит, что мне нужно прибить эти объекты.
Верно!
То есть, Вам нужно очистить список, Вы делаете <список>.clear().
А здесь с тобчность до наоборот в qDeleteAll, вдумайтесь.
Он прибивает объекты, так? А указатели - оставляет. Идиотизм.
ТО есть в контейнере по прежнему остается X указателей, которые никуда уже не указывают.

============================
Во всяком случае, приведите мне пример, когда после
qDeleteAll(someContainer) кому либо захотелось поиграться с указателями в someContainer.
Ну или примеры в студию )))



Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: SASA от Январь 26, 2011, 14:11
frostyland, я думаю, что Вы не правы в своей категоричности.
Функция qDeleteAll не является методом контейнеров. Она написана для удобства. qt - очень универсальный фреймворк. Из того, что Вы не можете придумать случай, когда qDeleteAll используется без clear, не следует то, что таких случаев нет. Если вам удобней пользоваться другой функцией, то напишите свою её
Код:
void myDeleteAll ( const Container & c )
{
    qDeleteAll(c);
    c.clear();
}

З.Ы. Я сам в 90% случаев использую qDeleteAll вместе с clear.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Январь 26, 2011, 14:19
Функция qDeleteAll не является методом контейнеров. Она написана для удобства.
Там ни слова про контейнеры, верно?
Код
C++ (Qt)
void qDeleteAll ( const Container & c )
This is an overloaded function.
This is the same as qDeleteAll(c.begin(), c.end()).
Лишь про интерфейс, безумно напоминающий интерфейс контейнера.
Да ладно, холивор. )))


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Январь 26, 2011, 14:28
Во всяком случае, приведите мне пример, когда после
qDeleteAll(someContainer) кому либо захотелось поиграться с указателями в someContainer.

Код
C++ (Qt)
struct MyData {
...
~MyData( void )  {}
 
int mType;
QString * mText;
...
};
 
void Data2Storage( QList<MyData> & src, QVector <QString *> & textStorage )
{
qDeleteAll(textStorage);
size_t i, limit = src.size();
textStorage.resize(limit);
for (i = 0; i < limit; ++i)
 textStorage[i] = src[i].mText;
}
 


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Январь 26, 2011, 15:10
Код
C++ (Qt)
struct MyData {
...
~MyData( void )  {}
 
int mType;
QString * mText;
...
};
 
void Data2Storage( QList<MyData> & src, QVector <QString *> & textStorage )
{
qDeleteAll(textStorage);
size_t i, limit = src.size();
textStorage.resize(limit);
for (i = 0; i < limit; ++i)
 textStorage[i] = src[i].mText;
}
 

В данном примере Вы не играетесь с невалидными указателями. Вы их тут же перезаписываете валидными.
Проблема данного Вашего кода в том, что Вы можете уверенно манипулировать данными только в данной видимости. В паре шагов от qDeleteAll...
То есть, сделав qDeleteAll(desperateContainer), мы получаем НЕПУСТОЙ контейнер со списком опасных хвостов - указателей на освобожденную память.
Не дай бог нам куда-нибудь его передать случайно за границы метода. Потому что там мы потеряем информацию, что память почищена, а хвосты остались!
Страшный и непредсказуемый desperateContainer, чей размер больше 0, но в нем полно бомб... о которых нам уже никто не подскажет...
Попробуй мы по нему итерировать desperateContainer.count(), foreach, или любые алгоритмы, меняющие данные - и нам пипец.

Почему я и говорю, что это слупый и опасный метод, уточню - при работе с контейнерами )))


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: BRE от Январь 26, 2011, 15:19
Почему я и говорю, что это слупый и опасный метод, уточню - при работе с контейнерами )))
Ну так и пользуйся этой функцией с осторожностью.  ;)
... также как и оператором delete, он тоже очень опасен тем, что не зануляет указатель на только что освобожденную память.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Январь 26, 2011, 16:36
> Там ни слова про контейнеры, верно?

Неверно.

Цитировать
Notice that qDeleteAll() doesn't remove the items from the container; it merely calls delete on them. In the example above, we call clear() on the container to remove the items.
This function can also be used to delete items stored in associative containers, such as QMap and QHash. Only the objects stored in each container will be deleted by this function; objects used as keys will not be deleted.



Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Январь 27, 2011, 08:02
Скажите, а почему Вас совершенно не волнуют соображения эффективности? Хотели ли мы освободить память занимаемую указателями? Не всегда, как показывает пример. Зачем тогда столько эмоций?  :)
2 момента.
1. Эффективность. Сомнительно. Сабж делетит память по указателям вызовом delete, это зачастую гораздо более затратно (ведь там скорее всего не new int хранились, а объекты каких-то реальных классов), нежели делетить потом сами указатели методом clear.
2. Безопасность. Еще раз скажу, см. мой пост выше. За пределами вызова qDeletaAll остается контейнер с неопределенным поведением, то есть, вдумайтесь! мы смотрим на непустой контейнер, и уже не знаем, а валиден ли он? А вдруг где-то в каком-то методе кто-то применил к нему qDeletaAll??? Это же невозможно узнать, не перелопатив вручную весь код (а если в поставке бинарники, то вообще невозможно).
Поэтому пользоваться этим глупым и опасным методом можно только так, как указано выше, то есть непосредственно в одном методе и только одному разработчику, который все знает про собственный стиль программирования )))

ЗЫ. ИМХО, эффективность в ущерб безопасности - это моветон. И, вообще смешно говорить об какой-то серьезной угрозе эффективности:
Код
C++ (Qt)
template <typename T>
Q_OUTOFLINE_TEMPLATE void QList<T>::clear()
{
   *this = QList<T>();
}
 
Скорее всего, просто недодумали ребята.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: asvil от Январь 27, 2011, 10:53
frostyland, наверно Вам просто стоит рассмотреть erlang или scheme, как вариант решения проблемы побочных эфектов.
Вы абсолютно верно замечаете факт наличия опасности в виде контейнера с невалидными указателями, но поймите кто-то программирует функции без уже упомянутых побочных эфектов и не может согласиться с Вашими доводами.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Январь 27, 2011, 17:47
frostyland, Ну тогда получается, что оператор delete тоже глупый и опасный.

Как уже было сказано выше, никто не мешает имплементировать qClearAll с нужным функционалом.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Kolobok от Январь 27, 2011, 18:05
frostyland, а как ты будешь QMap и QHash обрабатывать, если ключи тоже указатели и еще будут использоваться?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Январь 27, 2011, 18:15
frostyland, а как ты будешь QMap и QHash обрабатывать, если ключи тоже указатели и еще будут использоваться?
Ключ-указатель смысла не имеет т.к операторы  == и < не дадут разумного результата. А с мыслью согласен - ситуаций когда что-то остается невалидным после вызова метода или ф-ции сколько угодно


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: rp80 от Июнь 04, 2012, 18:07
Например с временными объектами.
Код:
for (int i = 0; i < topLevelItemCount(); ++i)
{
    qDeleteAll(topLevelItem(i)->takeChildren());
}

Здесь нет смысла чистить контейнер, так как он тут же удаляется.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 04, 2012, 18:44
Вот те пример:
Код
C++ (Qt)
class CTest
{
public:
 ~CTest()
 {
   qDebug()<<"die";
 }
};
//....
CTest* _array[] = {new CTest(),new CTest(),new CTest(),new CTest(),new CTest()};
qDeleteAll(_array, _array + COUNT(_array));
 
О том что контейнер не может поддерживать удаление элемента, ты не подумал?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 04, 2012, 21:25
Зачем нужен метод, чистящий память, но оставляющий в контейнере невалидные указатели?
Это абсолютно глупо! Нет ни одного случая, где бы эти указатели-хвосты могли бы понадобиться.
.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
Все равно приходится либо помнить об его вызове, либо писать свою над-функцию...
Совершенно непонятна такая стратегия  ???
qDeleteAll это алгоритм, а не метод!
Идите туда где вы учились и пусть там вам объяснят разницу между обобщенным программированием и объектно-ориентированным программированием.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 11:25
qDeleteAll это алгоритм, а не метод!
Идите туда где вы учились и пусть там вам объяснят разницу между обобщенным программированием и объектно-ориентированным программированием.
Вы, уважаемый хам, сейчас написали ерунду. qDeleteAll - это метод (function), что следует как из понятия "функция", так и из документации Qt на qDeleteAll (почитайте, это несложно, правда, по-английски).
И зачем Вы здесь приплели обобщенное программирование, мне тоже не понятно. Это никак не относится к вопросу. Умничаете?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: pastor от Июнь 05, 2012, 11:50
Цитировать
In the C++ programming language, algorithms are components that perform algorithmic operations on containers and other sequences. The C++ standard provides some standard algorithms collected in the <algorithm> standard header.

From Qt Reference Documentation:
Цитировать
Qt provides a number of global template functions in <QtAlgorithms> that work on containers and perform well-know algorithms.
qDeleteAll относится к этим функциям.


http://en.wikipedia.org/wiki/Method_(computer_programming)


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Июнь 05, 2012, 11:55
Если добросовестно изучать то всегда найдутся вещи которые, на наш взгляд, неудачны. Напр мне QPoint::x() кажется полной глупостью. Но я не навязываю своего мнения и не пытаюсь доказать типа "я грамотный и умный, а ты темный дурак"  :)


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Akon от Июнь 05, 2012, 12:34
qDeleteAll находит свое применение в типичных отношениях Parent - Children с двунаправленными связями. Т.е. мы можем делать delete child, и деструктор child удаляет свой указатель из контейнера, инкапсулированного в parent  (и делает другие побочные эффекты). Parent в деструкторе хачит детей с помощью qDeleteAll(), ничего больше не надо, контейнер при этом чистится автоматом.

Мне лень смотреть, но наверняка qDeleteAll используется в деструкторе QObject, поскольку там имеено такое отношение Parent - Children.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: mutineer от Июнь 05, 2012, 12:53
frostyland, а как ты будешь QMap и QHash обрабатывать, если ключи тоже указатели и еще будут использоваться?
Ключ-указатель смысла не имеет т.к операторы  == и < не дадут разумного результата. А с мыслью согласен - ситуаций когда что-то остается невалидным после вызова метода или ф-ции сколько угодно

QSignalMapper использует ключ-указель для QHash, и это имеет смысл


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 12:54
Никто тут за исключением одного умника никого дураком не мнит, друзья!
Я просто утверждаю, что за пределами видимости использования метода qDeleteAll вы получите скорлупку с гнилым содержимым, а не контейнер.

Еще раз, речь вот об этом.

Код
C++ (Qt)
class Test
{
public:
   Test(const char* text) : m_size(20), m_buf(0)
   {
       init(text);
   }
 
   ~Test()
   {
       if(m_buf != 0){
           free(m_buf);
       }
   }
 
   void init(const char* text)
   {
       if(m_buf == 0){
           m_buf = (char*)realloc(m_buf, m_size);
       }
       strncpy(m_buf, text, m_size-1);
   }
 
   const char* get() const
   {
       return m_buf;
   }
private:
   const int m_size;
   char* m_buf;
};
 
typedef QVector<Test*> TestVector_t;
 
void doItNice(TestVector_t& vector)
{
   qDeleteAll(vector);
   vector.clear();
}
 
void doItAsIdiot(TestVector_t& vector)
{
   qDeleteAll(vector);
}
 
 
int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
 
   const int _size = 10;
 
   {
       TestVector_t _vector;
       for(int _i = 0; _i < _size; ++_i){
           Test* _test = new Test("Nice and good!");
           _vector.push_back(_test);
       }
       int _count = _vector.size();
       doItNice(_vector);
       _count = _vector.size();
// Variant 1. OK! _count is valid!
       if(_count){
           for(int _i = 0; _i < _size; ++_i){
               Test* _obj = _vector[_i];
               const char* _str = _obj->get();
               printf(_str);
           }
       }
   }
 
   {
       TestVector_t _vector;
       for(int _i = 0; _i < _size; ++_i){
           Test* _test = new Test("Nice and good!");
           _vector.push_back(_test);
       }
       int _count = _vector.size();
       doItAsIdiot(_vector);
// Variant 2. FUCK! _count is fail!
       _count = _vector.size();
       if(_count){
           for(int _i = 0; _i < _size; ++_i){
               Test* _obj = _vector[_i];
               const char* _str = _obj->get();
               printf(_str);
           }
       }
   }
 
   return a.exec();
}
 

Variant 1
вот он - сторож контейнера - его размер.
Никак иначе не убедиться, что в контейнере ковыряться ОПАСНО!

Variant 2.
А здесь вы ПОПАЛИ!
Размер вас жестко обманет, и пипец памяти на машине клиента.
Он Вам однозначно скажет спасибо.
Как будете проверять? А??? А???

-----------------
Это опасное поведение. Вы никогда не можете предполагать, кто и как оперировал элеметами невалидного контейнера.
Писать такое, защищать такое - простительно 25-летним кодерам, которые еще институтские пирожки не повыкакали. Ну или тем, кто манипулирует только своим кодом, а никак не чужим. А если Вы, как иногда и я, работаете с чужим кодом, к исходника\м которого не имеете доступа, и вдруг получаете из какого нибудь метода ссылку на контейнер, Вам остается только молиться, что там не использовалось qDeleteAll без связки с clear...


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 13:08
Мне лень смотреть, но наверняка qDeleteAll используется в деструкторе QObject, поскольку там имеено такое отношение Parent - Children.
Что-то не нашел я там использования qDeleteAll. кутишнки сами используют крайне редко, только в деструкторах, ну и в примерах, всегда добавляя .clear()
даже себе они не позволяют лишний раз использовать эту бомбу замедленного действия...


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Июнь 05, 2012, 13:28
Еще раз, речь вот об этом.
Ну знаете, приведенный Вами текст содержит такие "пирожки" что по сравнению с ними qDeleteAll - да просто "персик" :)  Хотите - покритикуем


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 13:34
Я намеренно сделал его простым. Зато это работающий код, а не псевдо-лапша...
Концентрируйтесь на сути.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: m_ax от Июнь 05, 2012, 13:35
Цитировать
Это опасное поведение. Вы никогда не можете предполагать, кто и как оперировал элеметами невалидного контейнера.
Писать такое, защищать такое - простительно 25-летним кодерам, которые еще институтские пирожки не повыкакали. Ну или тем, кто манипулирует только своим кодом, а никак не чужим. А если Вы, как иногда и я, работаете с чужим кодом, к исходника\м которого не имеете доступа, и вдруг получаете из какого нибудь метода ссылку на контейнер, Вам остается только молиться, что там не использовалось qDeleteAll без связки с clear...

http://www.youtube.com/watch?v=urMtPiRUknY (http://www.youtube.com/watch?v=urMtPiRUknY)  
Не удержался)

А Вам сколько лет, если не секрет?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: kambala от Июнь 05, 2012, 13:35
Мне лень смотреть, но наверняка qDeleteAll используется в деструкторе QObject, поскольку там имеено такое отношение Parent - Children.
Что-то не нашел я там использования qDeleteAll. кутишнки сами используют крайне редко, только в деструкторах, ну и в примерах, всегда добавляя .clear()
даже себе они не позволяют лишний раз использовать эту бомбу замедленного действия...
поиск по исходникам дал 243 matches across 92 files - не так уж и редко. и clear() там вызывается далеко не везде.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Июнь 05, 2012, 13:41
Я намеренно сделал его простым. Зато это работающий код, а не псевдо-лапша...
Концентрируйтесь на сути.
Ой вряд ли он работающий. Значит, я так понял, критиковать не надо?  :)


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 13:46
поиск по исходникам дал 243 matches across 92 files - не так уж и редко. и clear() там вызывается далеко не везде.
1/2 - examples & demos, остальные - в деструкторах, или в связке. Просмотрел почти все вхождения.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 13:50
Ой вряд ли он работающий. Значит, я так понял, критиковать не надо?  :)
Елы-палы. Компилируйте, проверяйте, уважаемый (приаттачка).
Критикуйте СУТЬ топика - неотлавливаемые никак хвосты неинициализированной памяти после применения qDeleteAll.

Задача была показать на работающем коде опасность работы с контейнерами после операции над ними опасного и глупого метода qDeleteAll. Ключевое слово - работающий код. В противовес показана безопасность работы связки qDeleteAll+clear().

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


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Авварон от Июнь 05, 2012, 13:58
Не понимаю наездов хомячков на qDeleteAll. Он _намеренно_ сделан не очищающим контейнер, чтобы повысить производительность. Нахрена делать deleteAll и потом этот контейнер использовать? Я что-то задач мало вижу реальных. Он либо используется в деструкторе, либо не используется вовсе - в случае поштучной/груповой работы с контейнером.
А в тех случаях, когда нужно переиспользовать контейнер, можно и clear() написать - не обломитесь. С него, кстати, лучше начинать. Если вы напишите qDeleteAll() и забудете clear(), вы быстро об этом узнаете, поверьте.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 05, 2012, 14:09
прематуре оптимизайшен это что? это рут ов зе олл ивел, знаете ли ))))))) (http://yandex.ru/yandsearch?text=%D0%BF%D1%80%D0%B5%D0%B6%D0%B4%D0%B5%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F+%D0%BE%D0%BF%D1%82%D0%B8%D0%BC%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F&lr=54)

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

"Ваша программа постоянно падает"
"Зато она такая быстрая, что падает чаще других в один и тот же отрезок времени!!"


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 05, 2012, 14:18
Вы, уважаемый хам, сейчас написали ерунду. qDeleteAll - это метод (function), что следует как из понятия "функция", так и из документации Qt на qDeleteAll (почитайте, это несложно, правда, по-английски).
И зачем Вы здесь приплели обобщенное программирование, мне тоже не понятно. Это никак не относится к вопросу. Умничаете?
Читаем доку по QtAlgorithms (http://doc.qt.nokia.com/4.7-snapshot/qtalgorithms.html) там где-нибудь встречается слово метод? Нет там этого слова, и qDeleteAll не является членом-функцией какого либо класса. Однако там везде написано, что это алгоритмы. Читаем дальше там везде идут ссылки на STL (http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D0%B0%D1%8F_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2).
А STL это у нас:
Цитировать
набор согласованных обобщённых алгоритмов, контейнеров ...



Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Akon от Июнь 05, 2012, 14:22
2frostyland:
В тех примерах, что вы привели, использование qDeleteAll без clear - глупость. Никто вменяемый так не поступит. Но это не единственный способ использования qDeleteAll! Есть и другие способы, для которых qDeleteAll подходит.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 05, 2012, 14:25
.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
Не должен, т. к. требует от контейнера наличие этого самого clear()
Если у меня есть контейнер реализующий дерево или граф, то метод clear я захочу назвать как-нибудь по другому, что бы кто попало его не вызывал.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: Igors от Июнь 05, 2012, 14:27
Елы-палы. Компилируйте, проверяйте, уважаемый (приаттачка).
Критикуйте СУТЬ топика - неотлавливаемые никак хвосты неинициализированной памяти после применения qDeleteAll.
А Ваш текст компиляции не заслуживает.

1) strncpy не скопирует ноль-терминатор если размер исходной строки превысит m_size - 1. Вылет

2) Ни в печати, ни в init Вы не считаетесь с возможностью NULL-строки, а такой вариант рядовой. Вылет

3) Чего говорить о безопасности если не обеспечиваются конструктор копирования ни оператор присваивания? Такой класс Test - грабли на которые трудно не наступить

4) m_size(20) ... ну что сказать... формально "не ошибка", но профессионализмом и не пахнет

5) по меньшей мере на некоторых платформах realloc не освобождает память (напр realloc(4) не сократит размер блока что был 100k)

и.т.д

И вот Вы напускаетесь на безобидное qDleteAll и требуете от других "чистоты принципов", на которые сами плюете как хотите. Получается "вижу в чужом глазу сучок, а в своем и бревна не замечаю"  :) 


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 05, 2012, 14:28
Variant 1
вот он - сторож контейнера - его размер.
Никак иначе не убедиться, что в контейнере ковыряться ОПАСНО!

Variant 2.
А здесь вы ПОПАЛИ!
Размер вас жестко обманет, и пипец памяти на машине клиента.
Он Вам однозначно скажет спасибо.
Как будете проверять? А??? А???

А почему это у вас контейнер передается не константной ссылкой? А про пред и пост условия вы никогда не слышали?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 05, 2012, 14:31
Не понимаю наездов хомячков на qDeleteAll. Он _намеренно_ сделан не очищающим контейнер, чтобы повысить производительность. Нахрена делать deleteAll и потом этот контейнер использовать? Я что-то задач мало вижу реальных. Он либо используется в деструкторе, либо не используется вовсе - в случае поштучной/груповой работы с контейнером.
А в тех случаях, когда нужно переиспользовать контейнер, можно и clear() написать - не обломитесь. С него, кстати, лучше начинать. Если вы напишите qDeleteAll() и забудете clear(), вы быстро об этом узнаете, поверьте.
Вот тебе пример:
Реализуй обобщенный алгоритм перемещающий объекты из одного контейнера в другой. И перемести элементы из std::vector в std::set.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: DmitryM от Июнь 05, 2012, 14:42
.clear() просто должно было быть там по умолчанию в реализации qDeleteAll.
А что будет с итераторами этого контейнера, после вызова .clear()?


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: _OLEGator_ от Июнь 05, 2012, 14:45
Топик ни о чем. Написать туеву хучу текста, чтобы излить свое недоумение по поводу того, что ТС приходится писать clear() после использования qDeleteAll - это круто.
Всегда есть вариант написать свою реализацию, если что-то не нравится.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: twp от Июнь 06, 2012, 19:34
Поддерживаю _OLEGator_. Вообще с таким же успехом можно придраться к оператору delete который не обнуляет указатель после удаления. То может ТС лучше использовать java или С#


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: rp80 от Июнь 07, 2012, 17:57

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

"Ваша программа постоянно падает"
"Зато она такая быстрая, что падает чаще других в один и тот же отрезок времени!!"
Ну что ты за упертый тип ппц. Тебе все пытаются втолковать очевидную вещь, что далеко не всегда необходимо чистить контейнер после qDeleteAll. Посмотри пример что я писал выше. Его можно обобщить: очень часто контейнеры указателей используются в качестве локальных или временных объектов. Удалять содержимое необходимо, чтобы предотвратить  утечки памяти, а чистить его вовсе необязательно, он и так будет удален при выходе из области видимости,есть наверняка и другие подобные случаи.
Твои претензии можно с таким же успехом перенести к оператору delete[]. Мол почему он не обнуляет размер массива. Да потому что он и не должен этого делать.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: frostyland от Июнь 08, 2012, 17:16
Когда программист пишет программу, самое главное, о чем он должен думать – это надежность.
Надежность важнее скорости, она важнее даже красоты пользовательского интерфейса. Потому что пользователь скорее простит автору некоторые тормоза и кривизну цветов, нежели потерю данных или GPF в самый неподходящий момент.
И только обеспечив наиболее высокий уровень надежности, можно обратить внимание на скорость. Потому что а) можно удивиться, что скорость вполне устраивает всех, несмотря на то, что про нее не думали, и б) профилирование (именно профилирование) , покажет, что бутылочное горлышко производительности находится совсем не там, где программист предполагал.
После этого очень аккуратно можно заменять участки защищенного кода более безбашенным, но быстрым.

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

И концепт «не нравится надежность, напиши надежнее» должен быть безусловно заменен на правильный «не нравится скорость, напиши быстрее». А аргумент типа «delete вон тоже такой-сякой» является просто-напросто непрофессиональным подходом, ибо какого черта писать «полезный код» такого же низкого уровня надежности?

Что касается моего «ай-яй-яй» кода, то это называется «прототипирование».
В двух словах, задача такого кода – быстро проверить некоторые идеи, концепты, догадки. Задача очень узкая, делать его надо быстро, потому что главное – не этот код, а проверка, которую он осуществляет. Конечно, в нем много косяков, поэтому пишется он намеренно таким, чтобы не было соблазна потом вставить его в окончательный вариант программы. Для этого есть ряд техник, в  частности, писать на другом языке, обзывать его с префиксом prototype, test, etc…

Про все сказанное можно много где почитать, а я рекомендую отличную книгу Steve McConnell “Code Complete” Second Edition, значение которой в проектировании и написании грамотных программ трудно переоценить. В русском переводе она называется «Совершенный код».

-------------------------------------------------

))) Забавно, что в моих переписках с программистами из англоязычных стран таких рубиловок «Performance over reliability» вообще не возникает. Там это чаще всего вне дискуссий.


Название: Re: qDeleteAll - глупый и опасный метод!
Отправлено: _OLEGator_ от Июнь 08, 2012, 22:30
Спасибо конечно за ликбез, но тема яйца выеденного не стоит.

Просьба к админам перенести тему в говорилку.