pechkin: (Default)
pechkin ([personal profile] pechkin) wrote2005-01-23 03:40 pm

Тазом чувствую, что что-то неправильно, а что -- понять не могу:



void __fastcall MergeDataSets(TOAClientDataSet* cdsDst, TOAClientDataSet* cdsSrc, std::vector<const char*>& KeyFieldNames, std::vector<const char*>& CopyFieldNames)
{
  //собираю ключи, которые уже есть в датасете назначения
  std::set<std::vector<AnsiString> > existing_keys;
  for (cdsDst->First(); !cdsDst->Eof; cdsDst->Next())
    existing_keys.insert(CreateKeyVector(cdsDst, KeyFieldNames)); //функцию смотри ниже

  for (cdsSrc->First(); !cdsSrc->Eof; cdsSrc->Next())
  {
    //проверяю, что ключ из второго датасета не встречается в первом
    std::vector key = CreateKeyVector(cdsSrc, KeyFieldNames);
    if (existing_keys.find(key) == existing_keys.end())
    {
      //копирую из второго в первый
      //...


      existing_keys.insert(key);
    }
  }
  while (!existing_keys.empty())
  {
    //как бы, наверно, надо зачистить память, да?
    existing_keys.begin()->clear();
    existing_keys.erase(existing_keys.begin());
  }
}

Ключ -- это вектор, строящийся из строчных представлений значений полей, имена которых перечислены в векторе KeyFieldNames, порядок, естественно, важен.

std::vector __fastcall TfrmVersion::CreateKeyVector(TOAClientDataSet* cds, std::vector<const char*>& KeyFieldNames)
{
  unsigned key_length = KeyFieldNames.size();
  std::vector<AnsiString> key;
  for (unsigned i = 0; i < key_length; i++)
    key.push_back(cds->FieldByName(KeyFieldNames[i])->AsString);
  return key;
}

И вот подсказывает мне мой таз, что то ли память не зачищается где-то, то ли наоборот, объект удалится раньше, чем ссылки перестанут быть нужны.

[identity profile] matveich.livejournal.com 2005-01-23 06:26 am (UTC)(link)
Да вроде правильно всё.

Хм... а где дебагер падает?

[identity profile] pechkin.livejournal.com 2005-01-23 06:30 am (UTC)(link)
Еще пока нигде, и вообще, я начал решать эту проблему более вдумчиво и пришел к тому, что выигрыш в красоте кода не перевесит проигрыша в его эффективности.

А виртуальными функциями пользоваться в темплейтах нельзя-я.

[identity profile] cryinstone.livejournal.com 2005-01-23 06:48 am (UTC)(link)
С очисткой памяти все в порядке: existing_keys.begin()->clear() излишне: достаточно второй строчки с erase, which deletes entries in the range [First, Last). Более того, это нужно для правильной работы функции: утечка памяти невозможна в принципе, так как existing_keys создается на стеке функции и разрушается при выходе из оной, а заодно стирается его содержимое.

Во-вторых, здесь проблема куда серьезней: existing_keys не имеет оператора сравнения для его членов (в твоем случае это vector
[Error: Irreparable invalid markup ('<char*>') in entry. Owner must fix manually. Raw contents below.]

С очисткой памяти все в порядке: existing_keys.begin()->clear() излишне: достаточно второй строчки с erase, which deletes entries in the range [First, Last). Более того, это нужно для правильной работы функции: утечка памяти невозможна в принципе, так как existing_keys создается на стеке функции и разрушается при выходе из оной, а заодно стирается его содержимое.

Во-вторых, здесь проблема куда серьезней: existing_keys не имеет оператора сравнения для его членов (в твоем случае это vector<char*>). Кто сказал, что вектора равны, когда имеют одинаковую начинку. О правильном использовании std::set и задавании оператора сравнения для членов см. http://www.sgi.com/tech/stl/set.html

В третьих, кто сказал что виртуальными функциями пользоваться в темплейтах нельзя?

А в-четвертых, за такие постинги, тебя конечно следует разфрендить! :))

[identity profile] pechkin.livejournal.com 2005-01-23 07:00 am (UTC)(link)
1. А как насчет ключей, которые вектора, и которые создаются на стеке вообще другой функции?

2. А в хелпе написано, что у векторов есть оператор сравнения. Правда, как он работает, там не написано, но я почему-то решил, что именно так, как мне надо -- почленно.

3. Компилятор сказал. Я подумал, что, если проблема в том, что у разных датасетов разные ключи, то проблему решат

class KeyGenerator
{
public:
virtual Key GenerateKey(TOAClientDataSet* cds)=0;
}

class Key
{
public:
bool ExistsIn(std::set& keys)
{
for (std::set::iterator iter = keys.begin(); iter != keys.end(); ++iter)
if (!this->operator==(*iter))
return true;
return false;
}
//естественно,
virtual bool operator==(Key&)=0;
};

а от них уже наследовать хреновины для конкретных датасетов. И все было бы прекрасно, да нельзя, оказывается, темплейтным аргументам виртуальные функции пользовать.

4. "А кому смотреть противно, тот пускай и не глядит. Мы же в нос к нему не лезем? Пусть и он не пристает."

[identity profile] matveich.livejournal.com 2005-01-23 07:28 am (UTC)(link)
1. Esli na steke drugoi, to chistit togda nado po lubomu.
2. Esli v helpe napisano to togda tochno vse ok, t.k. drugovo logichnogo operatora == dlia vectora pridumat slozno.
3. Aga, reshat.

[identity profile] pechkin.livejournal.com 2005-01-23 07:32 am (UTC)(link)
2. Сложно -- но мы не боимся трудностей. Как какую глупость придумать, так мы вперед!

[identity profile] cryinstone.livejournal.com 2005-01-23 08:17 am (UTC)(link)
1. Ничего подобного! Было бы верно, если бы происходила аллокация из кучи. Если функция b() вызывается из функции a(), стек функции b() очищается по завершении функции, внутри а()! C++ Runtime элементарно возвращает стек-поинтер на нужную величину. Cтирается все содержимое стека b(), кроме обьекта, возвращаемого оператором return. Если рассмотреть подробно, что происходит в примере, будет так:
1) На стеке функции CreateKeyVector создается обьект key.
2) key возвращается в MergeDataSets
3) Обьект разрушается по завершении функции MergeDataSets (вызывается деструктор std::set к-рый заодно чистит его содержимое перед удалением обьекта).

2. Встроенный оператор сравнивания для вектора определен. Но я бы не стал на него полагаться. В нашем случае мы заносим char*, то есть поинтеры, которые равны только при равенстве самого физического адреса. Грубо, следуещее не всегда верно: ("Дима" == "Дима").

3. А вот компилятору верю! К тому же твое решение подходит и вполне красиво.

4. Шутка.

[identity profile] pechkin.livejournal.com 2005-01-23 08:24 am (UTC)(link)
2. Рассеял мои сомнения. Плохо быть недотепой.
3. Нет, оно подходит, конечно, но неосуществимо, поскольку классы с виртуальными абстрактными функциями не могут использоваться как темлпейтные аргументы. По крайне ймере, так говорит компилятор.

4. Шутки шутками, а отписываться от меня народ начал. Не вынесла душа поэта, типа.

[identity profile] ex-reaumur80.livejournal.com 2005-01-23 11:47 am (UTC)(link)
Печкин, ты фундаментально ошибаешься.

#include
using namespace std;

template
void f(T& obj) {
obj.f();
}

class A {
public:
virtual void f() = 0;
};

class B : public A {
public:
virtual void f() { cerr << "B\n"; }
};

void g(A& obj) {
f(obj);
}

int main() {
A* b = new B;
g(*b);
}

4. мстительно слежу за тем, как отписавшиеся от меня окружающие переживают из-за сокращения собственных френд-оф списков.

[identity profile] pechkin.livejournal.com 2005-01-23 11:58 pm (UTC)(link)
3. Слушай, но почему же тогда компилятор ругается?

4. Никогда не понимал, почему внимание или невнимание его мыслям должно расцениваться человеком как знак поощрения или наоборот... Мысли замерзли с утра, не получается.

[identity profile] ex-reaumur80.livejournal.com 2005-01-24 12:12 am (UTC)(link)
3. А ты мне покажи на что он именно ругается, я скажу -- почему.

Скорее всего, ты попытался хранить абстрактный класс "by value", а это -- грех.

4. Так как любой активный ЖЖ пишется для читателей, расширение аудитории показывает писателю, что его старания не пропадают даром. Соответственно, уменьшение аудитории действует в обратную сторону, утверждая что писанина -- скучная и никому не интересная.

[identity profile] pechkin.livejournal.com 2005-01-24 12:20 am (UTC)(link)
А. Ну, значит, у меня совершенно перпендикулярное какое-то отношение к ЖЖ. Тогда я автоматически выбываю из круга лиц, на которых можно обижаться за отфренживание. Или которых можно обидеть, отфрендив.

[identity profile] ex-reaumur80.livejournal.com 2005-01-24 12:22 am (UTC)(link)
Хм.
Чего тогда не пишешь в ноутпад, сохраняя в трипл-дес на флеш-карте, оснащенной биометрической защитой?

[identity profile] pechkin.livejournal.com 2005-01-24 12:27 am (UTC)(link)
Не люблю заморачиваться. :-)

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

[identity profile] ex-reaumur80.livejournal.com 2005-01-23 11:51 am (UTC)(link)
сравнение векторов -- лексикографическое. Мы сравниваем вектора AnsiString, я не знаю что это за тип, но если на нем определены операторы меньше и равно, то все пучком.

[identity profile] cryinstone.livejournal.com 2005-01-23 01:15 pm (UTC)(link)
Да, я как-то пропустил что vector от AnsiString, a не от char. Тогда должно быть хоккей. Все равно стоит проверить, как это дело работает.

А насчет (4) - я до сегодняшнего дня думал, что больше компилятору моего визуального восприятия никогда не предстанет токен TOAClientDataSet !!! :)))

[identity profile] ex-reaumur80.livejournal.com 2005-01-23 01:22 pm (UTC)(link)
Это что-то сакральное, TOA... (не произнося всуне)?

Вообще говоря, на множествах у нас есть стандартные операции типа set_union, set_intersection etc. Раз уж танцуем в сторону красивого кода, надо б о них подумать. Добавить генератор, построить два множества, и их объединить. Кррррасота. И дико медленно.

[identity profile] cryinstone.livejournal.com 2005-01-23 01:38 pm (UTC)(link)
TOAClientDataSet есть класс в одной конторе, где мы с г-ном Печкиным имели счастье работать вместе. Правда, я начал выпендриваться, за что меня оттуда недавно и поперли. С тех пор написатель сего находится в поисках программисткого джоба.

[identity profile] pechkin.livejournal.com 2005-01-24 12:01 am (UTC)(link)
Не надо медленно. Пусть лучше будет не очень красиво.

Хотя -- я тут человек маленький, могу и поизвращаться в свое удовольствие, никто особенно не заметит, а мне приятно.