информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Все любят медСетевые кракеры и правда о деле ЛевинаПортрет посетителя
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Очередное исследование 19 миллиардов... 
 Оптимизация ввода-вывода как инструмент... 
 Зловреды выбирают Lisp и Delphi 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
если вы видите этот текст, отключите в настройках форума использование JavaScript
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
[C++] Получилось хорошее решение (но я испортил нитку в форуме). 19.12.07 07:50  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 28.12.07 08:17  Количество правок: 4
<"чистая" ссылка> <обсуждение закрыто>
Прошу прощения, но я испортил нитку. Я хотел "ответить" на свой постинг в корень но каким -то образом затёр своё первое сообщение. Администраторы/модераторы - я не хотел..... ;( Если можно, то исправьте плз.
-----

В общем получилось весьма универсальное и производительное решение, см ниже.
Не map, а всё ж вектор. Работает быстро. Решение годится (протестировано) для 2-х типов задач:

- когда для обновлений добавляются относительно "статичные" топики, например, статусные переменные, результаты запросов к базам данных и т.д. Такие топики могут быть добавлены в вектор при помощи TopicVector::AddTopic и обновлены Subscriber-ом по таймеру.

- когда обновляются относительно "быстрые" топики 10000-15000 раз в секунду, например, данные для Microsoft RTD (real time data server). Не вдаваясь в обсуждение майкрософтовской трактовки "real time data", скажу, что данные накапливаются в TopicVector по приходу обновлений для топика при помощи TopicVector::UpdateTopic. Главный трюк - когда приходит обновление устанавливаем topic->m_cRef ++ , а когда Subscriber получает обновления из TopicVector, то он сбрасывает эти значения topic->m_cRef = 0.
Таким образом, вектор содержит единственное "вхождение" топика (как map), а данные всегда актуальны. Это в разы быстрее, чем map.

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


#include <string>
#include <vector>
#include "comdef.h"

const int INVALIDE_TOPIC_ID = -1;
const int TOPICVECTOR_RESERVE_SIZE = 500000;

typedef variant_t topic_t;

class Topic {
public:
virtual topic_t GetValue(void) const PURE;
Topic(long ID = INVALIDE_TOPIC_ID) : m_topicID(ID), m_cRef(0L) {};
virtual ~Topic(){};
long m_topicID;
long m_cRef;
};

class TopicVector
{
public:
void AddTopic(Topic* topic)
{
m_vector.push_back(topic);
topic->m_cRef ++;
}
void UpdateTopic(Topic* topic)
{
if ( 0 == topic->m_cRef)
m_vector.push_back(topic);
topic->m_cRef ++;
}
size_t Size(void) const
{
return m_vector.size();
}
bool IsValidTopic(const size_t idx) const
{
if (NULL != m_vector.at(idx) && INVALIDE_TOPIC_ID != m_vector.at(idx)->m_topicID )
return true;
else
return false;
}
Topic* operator[](const size_t idx)
{
return m_vector.at(idx);
}
void Lock(void)
{
::EnterCriticalSection(&m_cs);
}
void Unlock(void)
{
::LeaveCriticalSection(&m_cs);
}
void Clear(void)
{
m_vector.clear();
}
TopicVector()
{
::InitializeCriticalSection(&m_cs);
m_vector.reserve(TOPICVECTOR_RESERVE_SIZE);
}
~TopicVector()
{
::DeleteCriticalSection(&m_cs);
}

private:
std::vector<Topic*> m_vector;
CRITICAL_SECTION m_cs;
};
вот так было бы правильней, используя наследственность, ну... 20.12.07 02:13  
Автор: + <Mikhail> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
вот так было бы правильней, используя наследственность, ну естественно надо сделать private copy constructor и assignment operator.
Вообче то ето школьная задачка, не так ли?
class ITopic
{
public:
    virtual ~ITopic(){};
    virtual _bstr_t GetValue() = 0;
};
class CTopicVector
{
private:
    //I would use a smart pointer 
    //example:
    //map<int , smart_ptr<ITopic> > m_TopicData
    map<int , ITopic*> m_TopicData;
    CRITICAL_SECTION m_cs;
    
public:
    CTopicVector()
    {
        InitializeCriticalSection(&m_cs);
    };
    virtual ~CTopicVector()
    {
        ClearVector();
        DeleteCriticalSection(&m_cs);
    };
    
    void ClearVector()
    {
        map<int , ITopic*>::iterator it;
        EnterCriticalSection(&m_cs);
        try
        {
            for(it = m_TopicData.begin();it != m_TopicData.end();++it)
            {
                delete (*it).second;
            }
            m_TopicData.clear();
        }catch(...){};
        LeaveCriticalSection(&m_cs);
    }

    int GetSize()
    {
        return (int)m_TopicData.size();
    }
    int AddTopic(ITopic* pTopic)
    {
        int iId = (int)m_TopicData.size();
        EnterCriticalSection(&m_cs);
        try
        {
            m_TopicData[iId] = pTopic;
        }catch(...){}
        LeaveCriticalSection(&m_cs);
        return iId;
    };
    //unsafe reference to an object 
    ITopic* GetUnsafeTopic(int iId)
    {
        ITopic *pTopic = NULL;
        EnterCriticalSection(&m_cs);
        try
        {
            pTopic = m_TopicData[iId];
        }catch(...){}
        LeaveCriticalSection(&m_cs);
        return pTopic;
    }

};

class CTopic1: public ITopic
{
private:
    _bstr_t m_bstrVal;
    int     m_iVal;
public:
    CTopic1(_bstr_t bstrVal, int iVal)
        :m_bstrVal(bstrVal),m_iVal(iVal){}

    _bstr_t GetValue()
    {
        return m_bstrVal + L":" + _bstr_t(_variant_t(m_iVal)) + L"\n";
    }
};

class CTopic2: public ITopic
{
private:
    double  m_dVal;
    bool    m_bVal;
public:
    CTopic2(double dVal, bool bVal)
        :m_dVal(dVal),m_bVal(bVal){}

    _bstr_t GetValue()
    {
        return _bstr_t(_variant_t(m_dVal)) + L":" + (m_bVal?L"true\n":L"false\n");
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    CTopicVector TopicVector;
    TopicVector.AddTopic(new CTopic1(L"Topic1",1));
    TopicVector.AddTopic(new CTopic1(L"Topic1",2));
    TopicVector.AddTopic(new CTopic1(L"Topic1",3));
    TopicVector.AddTopic(new CTopic2(3.14,true));
    int size = TopicVector.GetSize();
    for(int i = 0; i < size; ++i)
    {
        ITopic* pTopic = TopicVector.GetUnsafeTopic(i);
        if(pTopic)
        {
            OutputDebugString(pTopic->GetValue());
        }
    }
    return 0;
}

---
> Буду рад и благодарен, если кто-нить подскажет элегантное
> решение. Задача такова:
> Есть произвольные структуры данных (векторы, массивы и т.д)
> classA {...}
> classBB {...}
> ....
>
> и есть векторы, массивы, мапы этих структур
>
> vector<A> va;
> vector<BB> vb;
> ...
>
> Каждый экземпляр таких структур/классов может
> быть”отображён” на более простой тип, например, строку,
> целое, булево и т.д. Т.е. Для каждого класса может быть
> определена некоторая функция, типа virtual variant_t
> GetTopicValue(const LPVOID pdata) const.
>
>
> Существует поток, в котором надо единообразно периодически
> “пробегать” по списку (контейнеру ссылок) всех этих
> элементов, с тем чтобы в цикле получать разультат
> “отображения” каждого экемпляра списка, например, в
> псевдокоде надо выполнить:
>
> loop for each in (va,vb, ...)
> v = each.GetTopicValue(NULL);
>
> Другие потоки добавляют в данный список ссылки на
> существующие структуры, например, когда данные обновлены.
>
> Я смотрел аналогичный код некоторых гурей, у которых я
> учусь– мне плохо стало от крутизны, непонятности,
> темплейтности, объектно ориентированности и ненужности.
> Попробовал сделать сам – получается просто, но хочется ещё
> более просто, изящно и элегантно. Попробовал темлейты
> прикрутить (как у гурей) – не получается чтоб это нужно
> было (от недостатка моих знаний, видимо). Наколеночный код
> у меня таков:
>
> #include "stdafx.h"
> #include <string>
> #include <vector>
> #include <sstream>
> #include "comdef.h"
>
>
> ///////////////////////////////////////////////////////////
> //////
> //
> // Generic topic containers
> //
> ///////////////////////////////////////////////////////////
> //////
>
> interface ITopic {
> virtual variant_t GetTopicValue(const LPVOID pdata)
> const PURE;
> virtual ~ITopic(){};
> };
>
> class Topic {
> public:
> virtual variant_t GetTopicValue(const LPVOID pdata)
> const
> {
> return (m_topicInterface ?
> m_topicInterface->GetTopicValue(pdata) : variant_t());
> }
> Topic() : m_topicID(0L), m_topicInterface(NULL) {}
> long m_topicID;
> ITopic* m_topicInterface;
> };
>
> class TopicVector
> {
> public:
> void AddTopic(const long ID, ITopic* item)
> {
> Topic topic;
> topic.m_topicID = ID;
> topic.m_topicInterface = item;
> m_vector.push_back(topic);
> }
> size_t Size(void) const
> {
> return m_vector.size();
> }
> Topic& operator[](const size_t idx)
> {
> return m_vector.at(idx);
> }
> void Lock(void)
> {
> ::EnterCriticalSection(&m_cs);
> }
> void Unlock(void)
> {
> ::LeaveCriticalSection(&m_cs);
> }
> TopicVector()
> {
> ::InitializeCriticalSection(&m_cs);
> }
> ~TopicVector()
> {
> Lock();
> for (size_t i = 0; i < m_vector.size();
> i ++)
> delete
> m_vector.at(i).m_topicInterface;
> Unlock();
> ::DeleteCriticalSection(&m_cs);
> }
> private:
> std::vector<Topic> m_vector;
> CRITICAL_SECTION m_cs;
> };
>
> ///////////////////////////////////////////////////////////
> //////
> //
> // Example: concrete topics
> //
> ///////////////////////////////////////////////////////////
> //////
>
> class ConcreteTopicA: public ITopic {
> public:
> virtual variant_t GetTopicValue(const LPVOID data)
> const
> {
> std::ostringstream s;
> s << m_sval << ":" <<
> m_ival;
> return _bstr_t(s.str().c_str());
> }
> ConcreteTopicA(const std::string& sval, const
> int ival): m_sval(sval), m_ival(ival) {};
> virtual ~ConcreteTopicA() {};
> private:
> std::string m_sval;
> int m_ival;
> };
>
> class ConcreteTopicB: public ITopic {
> public:
> virtual variant_t GetTopicValue(const LPVOID data)
> const
> {
> std::ostringstream s;
> s << m_bval << ":" <<
> m_fval;
> return _bstr_t(s.str().c_str());
> }
> ConcreteTopicB(const bool bval, const double&
> fval): m_bval(bval), m_fval(fval) {};
> virtual ~ConcreteTopicB() {};
> private:
> bool m_bval;
> double m_fval;
> };
>
>
> int _tmain(int argc, _TCHAR* argv[])
> {
> // create concrete topics
> ConcreteTopicA* topicA = new ConcreteTopicA("some
> string value", 100);
> ConcreteTopicB* topicB = new ConcreteTopicB(true,
> 1000.0);
>
> // add topics
> TopicVector topics;
> topics.Lock();
>
> topics.AddTopic(1, topicA);
> topics.AddTopic(2, topicB);
>
> //print it
> variant_t v;
> for (size_t i = 0; i < topics.Size(); i ++) {
> v = topics[i].GetTopicValue(NULL);
> // TO DO
> }
>
> topics.Unlock();
>
> return 0;
> }
>
> Спасибо, если кто предложит красивое, простое решение.
[C++] вот так было бы правильней, используя наследственность, ну... 21.12.07 04:40  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 21.12.07 04:42  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
> вот так было бы правильней, используя наследственность, ну
> естественно надо сделать private copy constructor и
> assignment operator.
> Вообче то ето школьная задачка, не так ли?

Так :(... Я бы даже сказал детсадовская... Но тем неменее могут быть и шероховатости!

> class ITopic
> {
> public:
> virtual ~ITopic(){};
> virtual _bstr_t GetValue() = 0;
> };

Я уберу virtual в определении деструктора ~ITopic. Эти указатели указывают на структуры данных, которые должны постоянно находиться в памяти и обновляться, возможно, из других потоков по наступлении некоторых событий.


> class CTopicVector
> {
> private:
> //I would use a smart pointer

Написал выше, что это нецелесообразно.


> //example:
> //map<int , smart_ptr<ITopic> > m_TopicData
> map<int , ITopic*> m_TopicData;

Возможно и не обойтись без map<int , ITopic*> vs vectior<Topic>. Но ... при использовании std::map мы можем сильно проиграть в производительности при большом числе элементов(~100 000) CTopicVector.
Ещё раз скажу о постановке задачи:

1)В начале цикла обработке CTopicVector::Size() == 0.
2) При поступлении обновлений данных, клиенты будут добавлять элементы при помощи AddTopic(ITopic* pTopic) в CTopicVector с указателями на свои структуры данных. Таким образом размер CTopicVector будет расти от нуля до некоторого значения N.
3)В некоторый момент (по таймеру, или условию N == MAX(N)) CTopicVector должен быть “flush” данные в некий процесс, и затем очищен. Функция, что ниже должна работать максимально быстро, чтобы не держать клиентов, обновляющих данные(ITopic, на некотором объекте синхронизации Lock()/Unlock():

STDMETHODIMP SomeObject::RefreshData( long *TopicCount,
SAFEARRAY **parrayOut)
{

...
// нечто вроде
Lock();
> int size = TopicVector.GetSize();
> for(int i = 0; i < size; ++i)
> {
> ITopic* pTopic = TopicVector.GetUnsafeTopic(i);
> if(pTopic)
> {
> OutputDebugString(pTopic->GetValue());
> }
> }
...
TopicVector.ClearVector()
Unlock();
}

Класс map куда более тяжелее в сравнении с vector при большом числе элементов (~100000) и при частом добавлении/удалении узлов. Напротив, для вектора можно “преаллокировать” сapacity(), так что освобождение вектора не будет приводить к фактической переаллокации памяти на глобальном хипе. В принципе, можно пойти дальше – создать массив вместо вектора в отдельном хипе. Пока не уверен, что это даст прирост производительности. Можно будет протестировать. И последнее, при интенсивных циклах создания/освобождения элементов TopicVector, при использовании vector или array не будет фрагментации памяти.


> CRITICAL_SECTION m_cs;
>
> public:
> CTopicVector()
> {
> InitializeCriticalSection(&m_cs);
> };
> virtual ~CTopicVector()
> {
> ClearVector();
> DeleteCriticalSection(&m_cs);
> };
>
> void ClearVector()
> {
> map<int , ITopic*>::iterator it;
> EnterCriticalSection(&m_cs);


Не пойдёт, см. ниже.


> try
> {
> for(it = m_TopicData.begin();it !=
> m_TopicData.end();++it)
> {
> delete (*it).second;
> }
> m_TopicData.clear();
> }catch(...){};
> LeaveCriticalSection(&m_cs);
> }
>
> int GetSize()
> {
> return (int)m_TopicData.size();
> }
> int AddTopic(ITopic* pTopic)
> {
> int iId = (int)m_TopicData.size();
> EnterCriticalSection(&m_cs);


Не пойдёт, см. ниже.


> try
> {
> m_TopicData[iId] = pTopic;
> }catch(...){}
> LeaveCriticalSection(&m_cs);
> return iId;
> };
> //unsafe reference to an object
> ITopic* GetUnsafeTopic(int iId)
> {
> ITopic *pTopic = NULL;
> EnterCriticalSection(&m_cs);
> try
> {
> pTopic = m_TopicData[iId];
> }catch(...){}
> LeaveCriticalSection(&m_cs);
> return pTopic;
> }
>
> };


Указанное выше “ниже” - это то, что блокировка должна охватывать весь процесс SomeObject::RefreshData. Иначе, данные CTopicVector будут неактуальными или испорченными другими клиентскими потоками, которые ” в этот момент” пытаются обновить свои структуры(ITopic. Даже если и не придавать значения такой “рассинхронизации” (не гут), то некоторые обновления и вовсе могут быть потеряны, т.к. по выходу из SomeObject::RefreshData вектор CtopicVector очищается. Поэтому необходимы отдельные методы Lock()/Unlock(). Другая причина в том, что вызов EnterCriticalSection – это не бесплатный вызов, даже если объект не блокируется (если критическая секция не занята, то на EnterCriticalSection может приходится ~ 100 тактов ЦПУ). Ну а если, уж объект синхнонизации блокирован, то дело совсем плохо. Поэтому нельзя, на мой взгляд, использовать такие Lock-и внутри циклов. Надо делать это снаружи циклов.

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

В целом я очень признателен Вам, даже несмотря на шероховатости обсуждаемых решений. Это придало мне уверенности, что тот код (не мой), который мне надо адаптировать – в топку и целиком.
Нууу, брат ты погнал, "Я уберу virtual в определении... 21.12.07 21:05  
Автор: + <Mikhail> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> > вот так было бы правильней, используя
> наследственность, ну
> > естественно надо сделать private copy constructor и
> > assignment operator.
> > Вообче то ето школьная задачка, не так ли?
>
> Так :(... Я бы даже сказал детсадовская... Но тем неменее
> могут быть и шероховатости!
>
> > class ITopic
> > {
> > public:
> > virtual ~ITopic(){};
> > virtual _bstr_t GetValue() = 0;
> > };
>
> Я уберу virtual в определении деструктора ~ITopic.
Нууу, брат ты погнал, "Я уберу virtual в определении деструктора ~ITopic"
сотри немедленно и считай что я не слышал :).

>Эти
> указатели указывают на структуры данных, которые должны
> постоянно находиться в памяти и обновляться, возможно, из
> других потоков по наступлении некоторых событий.
>
>
> > class CTopicVector
> > {
> > private:
> > //I would use a smart pointer
>
> Написал выше, что это нецелесообразно.
>
>
> > //example:
> > //map<int , smart_ptr<ITopic> >
> m_TopicData
> > map<int , ITopic*> m_TopicData;
>
> Возможно и не обойтись без map<int , ITopic*> vs
> vectior<Topic>. Но ... при использовании std::map мы
> можем сильно проиграть в производительности при большом
> числе элементов(~100 000) CTopicVector.
> Ещё раз скажу о постановке задачи:
>
> 1)В начале цикла обработке CTopicVector::Size() == 0.
> 2) При поступлении обновлений данных, клиенты будут
> добавлять элементы при помощи AddTopic(ITopic* pTopic) в
> CTopicVector с указателями на свои структуры данных. Таким
> образом размер CTopicVector будет расти от нуля до
> некоторого значения N.
> 3)В некоторый момент (по таймеру, или условию N == MAX(N))
> CTopicVector должен быть “flush” данные в некий процесс, и
> затем очищен. Функция, что ниже должна работать максимально
> быстро, чтобы не держать клиентов, обновляющих данные
>(ITopic, на некотором объекте синхронизации
> Lock()/Unlock():
>
> STDMETHODIMP SomeObject::RefreshData( long *TopicCount,
> SAFEARRAY **parrayOut)
> {
>
> ...
> // нечто вроде
> Lock();
> > int size = TopicVector.GetSize();
> > for(int i = 0; i < size; ++i)
> > {
> > ITopic* pTopic = TopicVector.GetUnsafeTopic(i);
> > if(pTopic)
> > {
> > OutputDebugString(pTopic->GetValue());
> > }
> > }
> ...
> TopicVector.ClearVector()
> Unlock();
> }
>
> Класс map куда более тяжелее в сравнении с vector при
> большом числе элементов (~100000) и при частом

Про количество елементов ты только сейчас заикнулся :)

> добавлении/удалении узлов. Напротив, для вектора можно
> “преаллокировать” сapacity(), так что освобождение вектора
> не будет приводить к фактической переаллокации памяти на
> глобальном хипе. В принципе, можно пойти дальше – создать
> массив вместо вектора в отдельном хипе. Пока не уверен, что
> это даст прирост производительности. Можно будет
> протестировать. И последнее, при интенсивных циклах
> создания/освобождения элементов TopicVector, при
> использовании vector или array не будет фрагментации
> памяти.

Фрагментация будет по любому, если ты конечно не преаллоцируешь память для твоих Topic objects

>
>
> > CRITICAL_SECTION m_cs;
> >
> > public:
> > CTopicVector()
> > {
> > InitializeCriticalSection(&m_cs);
> > };
> > virtual ~CTopicVector()
> > {
> > ClearVector();
> > DeleteCriticalSection(&m_cs);
> > };
> >
> > void ClearVector()
> > {
> > map<int , ITopic*>::iterator it;
> > EnterCriticalSection(&m_cs);
>
>
> Не пойдёт, см. ниже.
>
>
> > try
> > {
> > for(it = m_TopicData.begin();it !=
> > m_TopicData.end();++it)
> > {
> > delete (*it).second;
> > }
> > m_TopicData.clear();
> > }catch(...){};
> > LeaveCriticalSection(&m_cs);
> > }
> >
> > int GetSize()
> > {
> > return (int)m_TopicData.size();
> > }
> > int AddTopic(ITopic* pTopic)
> > {
> > int iId = (int)m_TopicData.size();
> > EnterCriticalSection(&m_cs);
>
>
> Не пойдёт, см. ниже.
>
>
> > try
> > {
> > m_TopicData[iId] = pTopic;
> > }catch(...){}
> > LeaveCriticalSection(&m_cs);
> > return iId;
> > };
> > //unsafe reference to an object
> > ITopic* GetUnsafeTopic(int iId)
> > {
> > ITopic *pTopic = NULL;
> > EnterCriticalSection(&m_cs);
> > try
> > {
> > pTopic = m_TopicData[iId];
> > }catch(...){}
> > LeaveCriticalSection(&m_cs);
> > return pTopic;
> > }
> >
> > };
>
>
> Указанное выше “ниже” - это то, что блокировка должна
> охватывать весь процесс SomeObject::RefreshData. Иначе,
> данные CTopicVector будут неактуальными или испорченными
> другими клиентскими потоками, которые ” в этот момент”
> пытаются обновить свои структуры(ITopic. Даже если и не

поетому smart poiter и нужен

> придавать значения такой “рассинхронизации” (не гут), то
> некоторые обновления и вовсе могут быть потеряны, т.к. по
> выходу из SomeObject::RefreshData вектор CtopicVector
> очищается. Поэтому необходимы отдельные методы
> Lock()/Unlock(). Другая причина в том, что вызов
> EnterCriticalSection – это не бесплатный вызов, даже если
> объект не блокируется (если критическая секция не занята,
> то на EnterCriticalSection может приходится ~ 100 тактов
> ЦПУ). Ну а если, уж объект синхнонизации блокирован, то
> дело совсем плохо. Поэтому нельзя, на мой взгляд,
> использовать такие Lock-и внутри циклов. Надо делать это
> снаружи циклов.
> И последняя шероховатость, которая не относится к
> эффективности, но к элегантности:
> и у Вас и у Нас есть по-существу GetUnsafeTopic, как Вы
> справедливо заметили . Ключевое слово здесь Unsafe, и я не
> знаю что с этим делать. Похоже этой неэлегантной
> шероховатости не избежать, так чтоб не родить другую
> неэлегантность.
>

поетому smart poiter и нужен


> В целом я очень признателен Вам, даже несмотря на
> шероховатости обсуждаемых решений. Это придало мне
> уверенности, что тот код (не мой), который мне надо
> адаптировать – в топку и целиком.

показал бы ТОТ код , который "не нужен"
Согласен, что погнал, но не только здесь 23.12.07 00:22  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> > Я уберу virtual в определении деструктора ~ITopic.
> Нууу, брат ты погнал, "Я уберу virtual в определении
> деструктора ~ITopic"
> сотри немедленно и считай что я не слышал :).

Я попробовал встоить код в существующий солюшен... Не работает.

> показал бы ТОТ код , который "не нужен"

Не могу. То собственность комании. Там активно темплейты используются.
А вот ещё мелькнуло... Может вообще не освобождать вектор в... 21.12.07 05:11  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
А вот ещё мелькнуло... Может вообще не освобождать вектор в методе RefreshData. Тогда, можно будет использовать map, и дополнительно устанавливать флаг = 1 если данные были обновлены клиентом (флаг = 1 устанавливается клиентом), и сбрасывать флаг в 0 в методе RefreshData.
Единственный недостаток пока вижу, это то, что если клиент перестал обновлять топик, (отсоединился), то соответствующуб ссылку надо удалить. Впрочем, это будет случаться не очень часто.

???

> STDMETHODIMP SomeObject::RefreshData( long *TopicCount,
> SAFEARRAY **parrayOut)
> {
>
> ...
> // нечто вроде
> Lock();
> > int size = TopicVector.GetSize();
> > for(int i = 0; i < size; ++i)
> > {
> > ITopic* pTopic = TopicVector.GetUnsafeTopic(i);
> > if(pTopic)
> > {
> > OutputDebugString(pTopic->GetValue());
> > }
> > }
> ...
> TopicVector.ClearVector()
> Unlock();
> }
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2025 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach