ononim wrote:
> ЗЫ А меня от всего МФСшного, включая CList несварение желудка случается. > Более отстойной библиотеки чем MFC пожалуй не найти.
Меня тоже от CList передёргивает, но попробуй на STD напиши коллекцию-
хранилище полиморфных объектов, которое бы само удаляло объекты
при удалении их из хранилища. (shared-ptr не предлагать — +4 байта на
каждый хранимый объект не катит). А на MFC-шных -- в момент пишется.
STL не различает ситуацию удаления элемента из коллекции и ситуацию
перенесения объекта из одного буфера коллекции в другой (новый).
Потому что академичный, блин.
MZ>Меня тоже от CList передёргивает, но попробуй на STD напиши коллекцию- MZ>хранилище полиморфных объектов, которое бы само удаляло объекты MZ>при удалении их из хранилища. (shared-ptr не предлагать — +4 байта на MZ>каждый хранимый объект не катит). А на MFC-шных -- в момент пишется.
в std алгоритмах бывает используются временные переменные, так что твое решение не катит.
формально, задачу решает наследование от std::vector<FooPtr> и нужного определение деструктора.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
MZ>>Вот кстати да. Почему бы не сделать было вместо итераторов MZ>>заклад на 3 функции : MZ>>-- size() MZ>>-- T& operator [] (unsigned n) MZ>>-- const T& operator [] (unsigned n) const
MZ>>Ничем не хуже.
ЮЖ>В случае, например списка, сложноть 'T& operator [] (unsigned n)' будет линейной, поэтому сложность перебора всех элементов с помощью этого интерфейса будет квадратичной.
Я делал себе такую штуку для множества, достаточно ввести m_nNextIndex и последовательный перебор всех значений (а у меня в основном такой) будет иметь обычную сложность.
Эх, люблю я цикл for( int i=0; i<set.GetCount(); i++) set[i];
night beast wrote:
> O> ZuPtr(T *t):_t(t) {} > O> ZuPtr(const ZuPtr &z):_t(z._t) {z._t = 0;} > O> ZuPtr &operator =(const ZuPtr &z){_t = z._t; z._t = 0; return *this;} > O> ~ZuPtr() {delete _t;} > O> T* operator ->(){return _t;}
> в std алгоритмах бывает используются временные переменные, так что твое > решение не катит.
А чем они мешают ... что-то не соображу.
Но могу сказать точно: первое расширение содержимого vesctor-а
вызовит деструкторы в старом "хранилище" и указатели в новом хранилище
уже будут невалидные -- все объекты будут удалены.
> формально, задачу решает наследование от std::vector<FooPtr> и нужного > определение деструктора.
Этого, блин, МАЛО. Нужно ещё заставить различаться ситуацию удаления
элементов НАСОВСЕМ от переноса их в новое хранилище.
Я ничего кроме написания собственного аллокатора с состоянием не
придумал. Решение непереносимо и ужасно.
Здравствуйте, MasterZiv, Вы писали:
MZ>Меня тоже от CList передёргивает, но попробуй на STD напиши коллекцию- MZ>хранилище полиморфных объектов, которое бы само удаляло объекты MZ>при удалении их из хранилища. (shared-ptr не предлагать — +4 байта на MZ>каждый хранимый объект не катит). А на MFC-шных -- в момент пишется.
Скорее, потому что в стандарте 98 нет move constructor.
А MFC-шные фокусы с memmove — имеют ограниченную применимость.
Но, если очень хочется, можно сделать руками.
vector<T> u, v;
....
// переносим задний элемент из u в v
// копированием (дорого)
v.push_back(u.back());
u.pop_back();
// обменом
v.push_back(T());
swap(u.back(), v.back();
u.pop_back();
Кодт wrote:
> Скорее, потому что в стандарте 98 нет move constructor.
Так почему было либо не добавить его туда
либо не использовать просто функцию ?
> А MFC-шные фокусы с memmove — имеют ограниченную применимость.
Ни разу ещё на это не напарывался.
Впрочем, я в своём коде давно отказался от использования MFC-шных
коллекций.
> Но, если очень хочется, можно сделать руками.
Я не про это. Я про перенос ЭЛЕМЕНТОВ коллекций из одного
хранилища в другое. При переносе вызываются конструктор
в новом месте (копирования) и деструктор в старом месте.
В случае удаления -- просто деструктор. Ну и как
определить, что элемент из коллекции удаляют насовсем ?
Только без защиты от использования с стандартными контейнерами, которые требуют от элементов, чтобы они были CopyConstructible и CopyAssignable, с обязательной эквивалентностью копий.
Здравствуйте, MasterZiv, Вы писали:
>> Скорее, потому что в стандарте 98 нет move constructor.
MZ>Так почему было либо не добавить его туда либо не использовать просто функцию ?
Добавить КУДА? в интерфейс произвольного объекта (рядом с ctor, cctor, dtor) или в интерфейс контейнера?
>> А MFC-шные фокусы с memmove — имеют ограниченную применимость.
MZ>Ни разу ещё на это не напарывался. MZ>Впрочем, я в своём коде давно отказался от использования MFC-шных коллекций.
>> Но, если очень хочется, можно сделать руками.
MZ>Я не про это. Я про перенос ЭЛЕМЕНТОВ коллекций из одного хранилища в другое. MZ>При переносе вызываются конструктор в новом месте (копирования) и деструктор в старом месте. MZ>В случае удаления -- просто деструктор. MZ>Ну и как определить, что элемент из коллекции удаляют насовсем ?
А его в обоих случаях удаляют насовсем.
Просто, вместо глубокого копирования и глубокого разрушения можно применить трюк с созданием пустого объекта и обменом содержимым.
Для POD-типов и некоторых других вместо обмена можно применить memmove, что, собственно, CArray и делает.
Или ты имеешь в виду именно списки?
Так у std::list есть функция splice, как раз для того, чтобы переносить цепочку узлов из одного контейнера в другой, без конструирования-разрушения.
Кодт wrote:
> Добавить КУДА? в интерфейс произвольного объекта (рядом с ctor, cctor, > dtor) или в интерфейс контейнера?
Да в стандарт. STL добавили, а
> А его в обоих случаях удаляют насовсем.
Здрасте, приехали.
> Просто, вместо глубокого копирования и глубокого разрушения можно > применить трюк с созданием пустого объекта и обменом содержимым. > Для POD-типов и некоторых других вместо обмена можно применить memmove, > что, собственно, CArray и делает. > > Или ты имеешь в виду именно списки? > Так у std::list есть функция splice, как раз для того, чтобы переносить > цепочку узлов из одного контейнера в другой, без конструирования-разрушения.
Нет, именно вектора.
Я не понимаю, как можно не понимать глубокой разницы между ПЕРЕМЕЩЕНИЕМ
элемента коллекции из одного хранилища в другое (что вообще-то внутреннее
дело коллекции и нас вообще касаться не должно) и УДАЛЕНИЕМ элемента или
добавлением элемента в коллекцию. Разные же вещи. В STL -- одно и то же.
В MFC-шных коллекциях различается чётко и ясно.
>> C>Поздравляю, ononim, Вы изобрели std::auto_ptr<T>: >> я знаю MZ>Интересно, а что std::auto_ptr<T> в стандартных контейнерах MZ>хранить нельзя, не знал ?
знал
но в некоторых реализациях STL можно
но так делать нельзя, я знаю
Как много веселых ребят, и все делают велосипед...
Здравствуйте, MasterZiv, Вы писали:
>> Добавить КУДА? в интерфейс произвольного объекта (рядом с ctor, cctor, >> dtor) или в интерфейс контейнера?
MZ>Да в стандарт. STL добавили, а
Ещё раз, куда в стандарт. Добавить move constructor, или метод vector::move_element_to_another_vector ?
>> А его в обоих случаях удаляют насовсем.
MZ>Здрасте, приехали.
И снова здравствуйте!
Объект располагается где-то в памяти. Когда мы освобождаем эту память (возвращаем её в кучу, либо оставляем пустой для грядущих добавлений), куда девается объект? Уничтожается.
Это тебе не управляемая среда вроде смолтока, явы или дотнета, где (в недрах менеджера памяти) можно взять и передвинуть кучу байтов с места на место, сохранив целостность ссылок на эти байты и из этих байтов.
А вот уничтожение, сопряжённое с копированием, можно реализовывать по-разному.
Либо через конструктор копирования и деструктор, либо через дефолтный конструктор, обмен и деструктор.
Деструктор будет в любом случае.
>> Или ты имеешь в виду именно списки?
MZ>Нет, именно вектора.
MZ>Я не понимаю, как можно не понимать глубокой разницы между ПЕРЕМЕЩЕНИЕМ MZ>элемента коллекции из одного хранилища в другое (что вообще-то внутреннее MZ>дело коллекции и нас вообще касаться не должно) и УДАЛЕНИЕМ элемента или MZ>добавлением элемента в коллекцию. Разные же вещи. В STL -- одно и то же. MZ>В MFC-шных коллекциях различается чётко и ясно.
Ну хорошо, в MFC/ATL есть у контейнеров метод RelocateElements.
И часто ты им пользуешься?
Вообще-то, он предназначен для внутренних нужд — через него реализованы функции вставки и удаления.
Переопределяя его (а лучше — не его, а трейтс-параметр шаблона CArray) ты можешь добиваться наилучшей и наиправильной работы этих функций. (Ибо, по дефолту там UB на memmove).
В STL перемещение элементов вектора спрятано внутрь и прибито гвоздями. Как именно — забота версии STL.
У Dinkumware (в поставке для VC) — там присваивания. Можно сделать через swap. Можно через копирования.
Для некоторых типов данных эффективнее swap, для других присваивание, для третьих копирование. (Ибо, по дефолту swap делается через копирование и два присваивания).
Вообще, идеология STL такова, что обычные контейнеры необязательно эффективны, но зато универсальны.
Когда возникает желание побороться за производительность, — пиши свой контейнер. Хочешь — делай его STL-like, не хочешь — не делай.
Присобачить STL-like интерфейс к CArray — раз плюнуть.
А с помощью буста можно и трейтсы с правильной реализацией RelocateElements на все случаи жизни (ну, хотя бы проверяя тип на POD и на известное семейство memmove-безопасных).
Здравствуйте, zitz, Вы писали: ЮЖ>>В случае, например списка, сложноть 'T& operator [] (unsigned n)' будет линейной, поэтому сложность перебора всех элементов с помощью этого интерфейса будет квадратичной. Z>Я делал себе такую штуку для множества, достаточно ввести m_nNextIndex и последовательный перебор всех значений (а у меня в основном такой) будет иметь обычную сложность. Z>Эх, люблю я цикл for( int i=0; i<set.GetCount(); i++) set[i];
В таком решении присутствует нарушение SRP — на контейнер возложено больше обязанностей, чем необходимо, соответственно на ровном месте возникает усложнение контракта контейнера и его реализации. Как следствие — потеря реентерабельности (см. сообщение Кодт'а). Кстати, перечисление в обратном порядке выполняется за O(n^2).
Здравствуйте, MasterZiv, Вы писали:
MZ>night beast wrote:
>> O> ZuPtr(T *t):_t(t) {} >> O> ZuPtr(const ZuPtr &z):_t(z._t) {z._t = 0;} >> O> ZuPtr &operator =(const ZuPtr &z){_t = z._t; z._t = 0; return *this;} >> O> ~ZuPtr() {delete _t;} >> O> T* operator ->(){return _t;}
>> в std алгоритмах бывает используются временные переменные, так что твое >> решение не катит.
MZ>А чем они мешают ... что-то не соображу.
по той-же причине, почему не рекомендуют хранить auto_ptr в стандартных контейнерах:
vector<FooPtr> v;
v.push_back( new Foo () );
{
FooPtr tmp = v[0]; // захватываем память
} // здесь мы освобождаем память
v[0]; // здесь имеем v[0] == 0;
MZ>Но могу сказать точно: первое расширение содержимого vesctor-а MZ>вызовит деструкторы в старом "хранилище" и указатели в новом хранилище MZ>уже будут невалидные -- все объекты будут удалены.
или я не понял задачу, или одно из двух;
расширение вектора не вызывает деструкторов хранящихся в нем объектов.
итераторы вектора да, становятся не валидными. хочешь обратного, используй list
>> формально, задачу решает наследование от std::vector<FooPtr> и нужного >> определение деструктора.
MZ>Этого, блин, МАЛО. Нужно ещё заставить различаться ситуацию удаления MZ>элементов НАСОВСЕМ от переноса их в новое хранилище. MZ>Я ничего кроме написания собственного аллокатора с состоянием не MZ>придумал. Решение непереносимо и ужасно.
деструктор это и есть удаление элементов насовсем.
можно более конкретно описать задачу?
night beast wrote:
> или я не понял задачу, или одно из двух; > расширение вектора не вызывает деструкторов хранящихся в нем объектов. > итераторы вектора да, становятся не валидными. хочешь обратного, > используй list
Ты уверен ?
> деструктор это и есть удаление элементов насовсем. > можно более конкретно описать задачу?
Да я уже описал. Хранить в коллекции (ну давай для конкретики вектор)
полиморфные объекты, унаследованные от класса, скажем, CMyFavoriteObject,
по ссылке, без дополнительных накладных расходов по памяти и так,
чтобы коллекция была бы ответственна за удаление этих объектов
(т.е. клиент удалил из коллекции элемент -- он удалился вообще,
т.е. delete).
Кодт wrote:
> Объект располагается где-то в памяти. Когда мы освобождаем эту память > (возвращаем её в кучу, либо оставляем пустой для грядущих добавлений), > куда девается объект? Уничтожается.
Ты по-моему совсем меня не понимаешь. Я совсем о другом.
> Ну хорошо, в MFC/ATL есть у контейнеров метод RelocateElements. > И часто ты им пользуешься?
Вообще не использую. Но там есть замечательный
глобальный метод типа
void AFXAPI DestructElements( MyClass **pElements, int nCount );
который достаточно определить для твоего хранимого
в контейнере типа и он будет вызываться при удалении
элементов из контейнера.
> Вообще, идеология STL такова, что обычные контейнеры необязательно > эффективны, но зато универсальны. > Когда возникает желание побороться за производительность, — пиши свой > контейнер. Хочешь — делай его STL-like, не хочешь — не делай.
Дело не в производительности, а именно в универсальности. Перемещение
элемента в другое хранилище -- отдельная операция, она НЕ СВЯЗАНА
с удалением объекта вообще никак. Так вот именно она должна
была специфицирована в стандарте и как-то реализована. Но ребята
решили притвориться академиками и не париться. Конструктор-деструктор.
Типа другого пути нет.
Здравствуйте, MasterZiv, Вы писали:
>> или я не понял задачу, или одно из двух; >> расширение вектора не вызывает деструкторов хранящихся в нем объектов. >> итераторы вектора да, становятся не валидными. хочешь обратного, >> используй list
MZ>Ты уверен ?
был уверен. посмотрел -- облом
в оправдание могу сказать, что пользуюсь своими поделками
>> деструктор это и есть удаление элементов насовсем. >> можно более конкретно описать задачу?
MZ>Да я уже описал. Хранить в коллекции (ну давай для конкретики вектор) MZ>полиморфные объекты, унаследованные от класса, скажем, CMyFavoriteObject, MZ>по ссылке, без дополнительных накладных расходов по памяти и так, MZ>чтобы коллекция была бы ответственна за удаление этих объектов MZ>(т.е. клиент удалил из коллекции элемент -- он удалился вообще, MZ>т.е. delete).
boost::ptr_vector (уже было озвучено) не подходит?
Здравствуйте, MasterZiv, Вы писали:
MZ>Дело не в производительности, а именно в универсальности. Перемещение MZ>элемента в другое хранилище -- отдельная операция, она НЕ СВЯЗАНА MZ>с удалением объекта вообще никак. Так вот именно она должна MZ>была специфицирована в стандарте и как-то реализована. Но ребята MZ>решили притвориться академиками и не париться. Конструктор-деструктор. MZ>Типа другого пути нет.
Ты, видимо, упорно путаешь CArray и его производные — CPtrArray, CObArray.
Их элементы — указатели. Понимаешь, указатели, а не указуемые значения.
Если тебе хочется, чтобы контейнер выполнял глубокое копирование и глубокое удаление (указателей вместе с указуемыми) — пожалуйста, boost::ptr_vector.
Или vector<shared_ptr>, если не хочешь иметь разные траблы с монопольным владением.