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

Ваш аккаунт

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

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

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

По поводу vector<>

1
06 октября 2003 года
kot_
7.3K / / 20.01.2000
Ситуация следующая:
есть класс к примеру myClass объявленный примерно так
class myClass:private myBaseClass{
private:
typedef vector<Class>ListClass;
...
...
ListClass listclass;
}
Объекты данного класа помещаются в другом классе в map. Т.е.
class MyListClass{
typedef map<myClass>ListMyClass;
...
...
ListMyClass listmyclass;
}
Все функции необходимые для помещения извлечения и пр. реализованы и работают.
За исключением одного но - когда я считываю из мапа объекты класса - то listclass для всех объектов одинаков. Как это побороть? Мне необходимо что бы каждый объект myClass содержал уникальный вектор для каждого элемента. Может есть какие то идеи?
3
06 октября 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_
Ситуация следующая:
есть класс к примеру myClass объявленный примерно так
class myClass:private myBaseClass{
private:
typedef vector<Class>ListClass;
...
...
ListClass listclass;
}
Объекты данного класа помещаются в другом классе в map. Т.е.
class MyListClass{
typedef map<myClass>ListMyClass;
...
...
ListMyClass listmyclass;
}
Все функции необходимые для помещения извлечения и пр. реализованы и работают.
За исключением одного но - когда я считываю из мапа объекты класса - то listclass для всех объектов одинаков. Как это побороть? Мне необходимо что бы каждый объект myClass содержал уникальный вектор для каждого элемента. Может есть какие то идеи?



Ну он и должен быть уникален, он же не static.
Проверь, что у тебя классы соответствуют требованиям контейнеров, а именно:
- имеют конструктор поумолчанию,
- имеют конструктор копирования,
- иногда требуется еще и operator=
Проблема может быть еще и в том, как ты заполняешь vector и map.
Короче, надо смотреть подробнее.

И еще, не относящееся к этой проблеме, ты уверен, что тебе нужен vector, а не list или даже queue?

1
06 октября 2003 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green


Ну он и должен быть уникален, он же не static.
Проверь, что у тебя классы соответствуют требованиям контейнеров, а именно:
- имеют конструктор поумолчанию,
- имеют конструктор копирования,
- иногда требуется еще и operator=
Проблема может быть еще и в том, как ты заполняешь vector и map.
Короче, надо смотреть подробнее.

И еще, не относящееся к этой проблеме, ты уверен, что тебе нужен vector, а не list или даже queue?


Да мне то нужен простой шаблон, в который помещаются классы, как раз вектора с головой хватает. Просто проблема загадочная...:x Запись из файла, запись в файл - все работает на ура - классы добавляются без проблем...а вот стал работать с отдельными элементами меп'а - и вдруг такая неприятность. Вектор заполнен так как надо, только все классы обращаются к одному и тому же.
А это не есть здорово.

1
07 октября 2003 года
kot_
7.3K / / 20.01.2000
Спасибо всем, проблема решилась.
Проблема была в том, что базовый класс был по началу совсем не базовым а конкретным, и с тех времен в нем был использован:
typedef vector<Class>ListClass;
...
ListClass listclass;
и вроде как происходило перекрывание пространства имен. Базовый класс создается один раз, поэтому и возникал единый массив для всех объектов. Может и не совсем верно, с точки зрения теоретической, но практически заработало...:)
3
07 октября 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_
и вроде как происходило перекрывание пространства имен.


Это как?

Цитата:
Originally posted by kot_
Базовый класс создается один раз, поэтому и возникал единый массив для всех объектов.


Класс создается? В C++ классы сами не создаются, создаются екземпляры классов

Цитата:
Originally posted by kot_
Да мне то нужен простой шаблон, в который помещаются классы,


Интересное заявление... Может все же нужен контейнер, а не любой шаблон. :D

Цитата:
Originally posted by kot_
как раз вектора с головой хватает.


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

1
07 октября 2003 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green

Это как?


Честно говоря - не знаю. Это мое предположение, не подтвержденное пока ничем. После удаления вектора из базового класса - все вроде заработало, потом опять начали возникать проблемы, в конце концов, от вектора в качестве поля класса я просто отказался. просмотр доков, как по Билдеру так и просто по С++ ничего не дал. Ни единого упоминания о чем либо подобном мне не встретилось. Правда в одном моменте проскочила рекомендация в случае использования шаблонов - контролировать копирование и создание объектов класса - но в связи с чем и какие проблемы могут возникнуть???? И возможно ли их обойти? Ни гу-гу.

Цитата:
Originally posted by Green

Класс создается? В C++ классы сами не создаются, создаются екземпляры классов


Прошу прощения, именно это и имелось подразумевалось.

Цитата:
Originally posted by Green

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


Как раз вектор для данной задачи и наиболее подходил. Потому как, кроме однократной вставки элементов и получения элементов по индексу - ни каких операций более не проектировалось. И лист и дек для этих целей чересчур. Да и собственно проблему в конечном итоге они не решают.

3
07 октября 2003 года
Green
4.8K / / 20.01.2000
Интересно разобраться до конца.
Значит все было примерно так:
Код:
class myBaseClass
{
private:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class myClass :private myBaseClass
{
private:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class MyListClass
{
    typedef map<myClass> ListMyClass;
    ListMyClass listmyclass;
};


Т.о. в классе myClass существуют два вектора:
myClass::listclass;
и
myClass::myBaseClass::listclass;

Причем второй недоступен даже из самого класа, если в базовом он объявлен, как privat.

Если методы работы с вектором были расположены в базовом классе, то они и работать будут только с вектором расположенном в базовом классе. Методы расположенные в дочернем классе будут работать в данном случае только с вектором расположенном в этом же дочернем классе.

Может приведешь код по-подробнее. Что за класс Class используется у тебя в векторе?

Цитата:
Originally posted by kot_
Правда в одном моменте проскочила рекомендация в случае использования шаблонов - контролировать копирование и создание объектов класса



Ты, видимо, путаешь понятия шаблона и контейнера.
vector, list, queue - это контейнеры,
а шаблоны - это совершенно другое понятие, это классы объявленные как
temlate<class T, .....> class ClassName;

1
07 октября 2003 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green
Интересно разобраться до конца.
Значит все было примерно так:
Код:
class myBaseClass
{
private:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class myClass :private myBaseClass
{
private:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class MyListClass
{
    typedef map<myClass> ListMyClass;
    ListMyClass listmyclass;
};


Т.о. в классе myClass существуют два вектора:
myClass::listclass;
и
myClass::myBaseClass::listclass;

Причем второй недоступен даже из самого класа, если в базовом он объявлен, как privat.

Если методы работы с вектором были расположены в базовом классе, то они и работать будут только с вектором расположенном в базовом классе. Методы расположенные в дочернем классе будут работать в данном случае только с вектором расположенном в этом же дочернем классе.

Может приведешь код по-подробнее. Что за класс Class используется у тебя в векторе?



Все было так:

Код:
class myBaseClass
{
protected:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class myClass :private myBaseClass
{
private:
    typedef vector<Class> ListClass;
    ListClass listclass;
};

class MyListClass
{
    typedef map<myClass> ListMyClass;
    ListMyClass listmyclass;
};

Собственно код класса сброшу чуть позже сегодня или завтра, а то у меня на машине сети нет, а носится сейчас с дискетами - просто нет времени.
Все функции для работы с вектором использовались из производного класса, т.ч. проблемы вродеи быть не должно...
1
07 октября 2003 года
kot_
7.3K / / 20.01.2000
Хех...продолжим...
Вот класс, объект которого собственно хотелось поместить в вектор :
Код:
#ifndef ScladProdH
#define ScladProdH
#include "ProductHigh.h"
#include "Structures.h"
 class TScladProd:private TProductHigh{
 public:
  TScladProd();

  TScladProd(const TScladProd&);
  int __fastcall GetCode()const {return recordId_;}
  void __fastcall SetCode(int i){recordId_=i;}

  ...

  TDateTime __fastcall GetData3()const{return Data3;}
  void __fastcall SetData3(const TDateTime& data){Data3 = data;}

  TDateTime __fastcall GetTime ()const{return Time;}
  void __fastcall SetTime(const TDateTime& time){Time = time;}

  float __fastcall GetCount(){return Count;}
  void __fastcall SetCount(const float& count){Count = count;}
  //Перегруженный оператор потока для записи в файл
  void __fastcall operator >> (TScladLow&);
 //Перегруженный оператор присваивания, для считывания
//Запись и считывание производится через структуру фиксированного размера
 void __fastcall operator = (const TScladLow& a2);
  protected:
  int DocCode;
  int InCode;
  TDateTime Data1;
  TDateTime Data2;
  TDateTime Data3;
  TDateTime Time;
  float Count;
 };
bool operator < (const TScladProd&,const TScladProd&);

Существует базовый класс документа:
Код:
#ifndef DocumentHighH
#define DocumentHighH
//---------------------------------------------------------------------------
#include <systdate.h>
#include <vector.h>
#include <algorithm.h>
#include "ScladProd.h"
class TDocumentHigh{
 protected:
 typedef vector<TScladProd>ListProd;
 public:
   TDocumentHigh(TDocumentLow&);
   TDocumentHigh(){}
   ~TDocumentHigh(){}

   int insertProduct(const TProductHigh& pord);
   void eraseProduct(int recordId);

   const TProductHigh& getProduct(int recordId)const;

   ...
   void operator=(const TDocumentLow&);
   void operator>>(TDocumentLow&);

 protected:
   int Code;
   AnsiString Name;
   TDateTime Data;
   TDateTime Time;
   double Amount;
   int Client;
   int Meneger;
   int ProductCount;
   bool Delete;
 ListProd productlist;
};
   bool operator < (const TDocumentHigh&,const TDocumentHigh&);

Часть переменных объявлена в базовом классе, они общие для всех классов продуктов.
Следующий - класс документа, который должен содержать или указатели на объекты, или массив объектов типа TScladProd:
Код:
#ifndef InvoceInH
#define InvoceInH
//---------------------------------------------------------------------------
#include "ScladProd.h"
#include "Structures.h"
class TInvoiceIn:private TDocumentHigh{
protected:
typedef vector<TScladProd>ListProd;
public:
 TInvoiceIn();
 TInvoiceIn(const TInvoiceIn& a2);
   //Вставляет в вектор объект класса функцией push_back()
   int insertProduct(const TScladProd&);
   void Copy(const TInvoiceIn&);
  //Возращает обект через индекс
   const TScladProd getProduct(const int&)const;

  ...

   int GetProductCount(){return ProductCount;}
   void SetProductCount(const int& s) {ProductCount = s;}

  void operator = (TDocumentLow&);
  void operator >>(TDocumentLow&);

  protected:
 ListProd productlist;
 
};
   bool operator < (const TInvoiceIn&,const TInvoiceIn&);

Функции открытого интерфейса, я убираю, т.к. они роли большой не играют и возращают занчения типа кода, имени и т.п. Все переменные объявлены в базовом классе и наследуются оттуда.
И собственно клас который работает с объектом документов выглядит вот так
Код:
#ifndef ListDocumentH
#define ListDocumentH
#include <set.h>
#include <map.h>
#include "InvoceIn.h"
#include "ScladProd.h"
#include "Errors.h"
//---------------------------------------------------------------------------
class TListDocument
{
 typedef multiset<TInvoiceIn>DocumentName;
 typedef map<int,DocumentName::iterator>DocumentCode;
  public:
   TListDocument();
   ~TListDocument();
   void __fastcall LoadFromFile(const AnsiString& f);
   void __fastcall SaveToFile(const AnsiString& f);
   int __fastcall insertDocument(const TInvoiceIn& doc,int recodId = 0)throw (DuplicateId);
   int __fastcall Size(){return documentname.size();}
   void __fastcall eraseDocument(int recordId);
   void __fastcall replaseDocument(const TInvoiceIn& doc,int recordId = 0);


   int __fastcall countName(const AnsiString& name,const AnsiString Packed)const;
   typedef DocumentName::const_iterator c_iter;
   c_iter __fastcall begin() const{return documentname.begin();}
   c_iter __fastcall end() const{return documentname.end();}
   c_iter __fastcall findNameStartsWith(const AnsiString& Name, const AnsiString& packed = "кг.")const;
   c_iter __fastcall findNextContains(const AnsiString& searchStr,c_iter start)const;
   c_iter __fastcall findId(int recordId)const;
   c_iter __fastcall findMaxId()const;
   c_iter __fastcall findMinId()const;
   TScladProd __fastcall findProd(const int& recordId);
   AnsiString __fastcall CountIn(const int&recordId);
   AnsiString __fastcall CountOut(const int&recordId);
   c_iter Document;
   
  private:
   TListDocumet(const TListDocument&);
   TListDocument& operator=(const TListDocument&);
   static int nextId;
   DocumentName documentname;
   DocumentCode documentcode;
   void insertDocument(const TDocumentHigh& doc);
   void  __fastcall clearAll();

   DocumentName::iterator __fastcall TListDocument::getByCode (int recordId)throw(DocumentNotFound);

};

#endif

Объект этого класса содержит список документов и список кодов документов. Код документа не может быть продублирован.
ну вот вроде бы и все. Рализация классов достаточно стандартна. Если сможешь что либо подсказать - буду благодарен. На сейчас я уже переделал все без векторов, но получается не так удобно...:(
3
09 октября 2003 года
Green
4.8K / / 20.01.2000
Без реализаций, конечно, сложно анализировать, но вот что я накопал.
Какой смысл в базовом классе TDocumentHigh, если все методы переопределены, и они не виртуальные. Он только вносит путаницу, например, в классе TInvoiceIn существуют два вектора:
- собственный TInvoiceIn::productlist,
- и доставшийся в наследство TInvoiceIn::TDocumentHigh::productlist.

Зачем в TListDocument используется связка multiset и map ?
TListDocument::next Id действительно должен быть статиком?
В TListDocument::insertDocument в качестве аргумента принимается ссылка на TDocumentHigh, а не на TInvoiceIn. Это может быть ошибкой.

И еще. IMHO, все operator< целесообразней внести внутрь соотв. классов.
1
09 октября 2003 года
kot_
7.3K / / 20.01.2000
Спасибо за подробный ответ, попытаюсь прояснить.
Реализации я не выкладывал, так как не имею привычки писать комментарии - а в своей мешанине кода, я сам иногда не могу вспомнить нафига то или это. Когда приведу все в порядок - если будет интересно сброшу...
Цитата:
Originally posted by Green
Без реализаций, конечно, сложно анализировать, но вот что я накопал.
Какой смысл в базовом классе TDocumentHigh, если все методы переопределены, и они не виртуальные. Он только вносит путаницу, например, в классе TInvoiceIn существуют два вектора:
- собственный TInvoiceIn::productlist,
- и доставшийся в наследство TInvoiceIn::TDocumentHigh::productlist.


Да никакого сбств. Пробную версию надо было сдать в понедельник...а на сегодня еще печать не реализована..:)В начале планировалось что этот класс будет чисто виртуальным, а от него будут наследовать. Потом необходимость пока отпала, а там видно будет. От веторов на сегодня я полностью отказался - и проблемой меньше стало.

Цитата:

Зачем в TListDocument используется связка multiset и map ?
TListDocument::next Id действительно должен быть статиком?
В TListDocument::insertDocument в качестве аргумента принимается ссылка на TDocumentHigh, а не на TInvoiceIn. Это может быть ошибкой.


Связка нужна что бы эффективно реализовать операции поиска по произвольному значению,редактирование и удаление объектов с одной стороны, и эффективный поиск и вставка по ключу, с другой стороны.
мультисет позволяет сортировать массив по произвольным полям, соответственно, эффективность поиска значительно повышается. Мап - эффективно сортирует по ключу, и ключ должен быть уникальным. При вставке генерируется исключение - не нужно искать дубликаты. Ну и еще ряд преимуществ. В паре все работает гораздо эффективние. Статическая переменная нужна что бы можно было контролировать код объекта и автоматически его присваивать. Выглядит вот так:

Код:
int __fastcall TListDocument::insertDocument(const TInvoiceIn& doc,int recordId)throw(DuplicateId){
//если в фукцию передан объект без ИД присваиваем значение и увеличиваем статическую переменную
 if(recordId ==0)recordId = nextId++;
//Просто увеличиваем значение на ИД+1, если нужно
 else if(recordId >= nextId)nextId = recordId +1;
//Ключ может быть только один - потому исключаемся
else if (documentcode.count(recordId))throw DuplicateId();
 TInvoiceIn *docum = new TInvoiceIn(doc);
 docum->SetCode(recordId);
//Вставляем объект и получаем итератор на него
 DocumentName::iterator i=documentname.insert(*docum);
//Вставляем ключ и итератор
 documentcode[recordId] =i;
 return recordId;
}

Прикол в том еще что собственно ни мультисет, ни мультимап ни им подобные контейнеры возращают, как ты заметил, не позицию элемента - а итератор на него...и если правило сортировки и меня не по коду(а оно таки не только по коду), то что бы найти нужный код надо крутить весь массив - т.е. линейный поиск - т.е. сам понимаешь, если три объекта - еще ладно...а если бо-о-ольше...
мап делает это чисто и эффективно...:)
Цитата:

И еще. IMHO, все operator< целесообразней внести внутрь соотв. классов.


Я IMHO, тоже так думал - пока не ввел...:)
Дело в том, что функции STL и контейнеров нуждаются в перегруженных операторах сравнения, но весь прикол в том, что объект функции должен получить ДВА аргумента - начальный и конечный итераторы, а фунция-член класса operator может принять только один...:) Выходов из этого положения может быть несколько каждый имеет свои достоинства и недостатки. Но для меня задача сейчас - оптимально организовать программу - после этого имеет смысл приступать к тестированию эффективности классов.
Но все таки любопытно, получается контейнер не может быть членом класса? Если есть под рукой вижуалка можно попробовать смоделировать ситуацию на ее компиляторе.

3
10 октября 2003 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by kot_

Но все таки любопытно, получается контейнер не может быть членом класса? Если есть под рукой вижуалка можно попробовать смоделировать ситуацию на ее компиляторе.



Да нет, что ты!
Вектор, как и объект любого другого класса, может быть челеном другого класса. Это 100%!
На контейнерах основаны некоторые умные указатели (smart pointers) и т.п.
Твоя проблема в реализации роботы с вектором.

1
10 октября 2003 года
kot_
7.3K / / 20.01.2000
Цитата:
Originally posted by Green


Да нет, что ты!
Вектор, как и объект любого другого класса, может быть челеном другого класса. Это 100%!
На контейнерах основаны некоторые умные указатели (smart pointers) и т.п.
Твоя проблема в реализации роботы с вектором.


Ладно, позже еще вернусь к этому. Я кстати порылся в старых своих прогах, и вспомнил, что уже реализовал класс с вектором...но там немного другая задача была. Ладно посмотрим. Спасибо за участие...:)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог