Расширение созданного экономным объектом в C ++ - PullRequest
1 голос
/ 01 августа 2011

Используя следующий .thrift файл

struct myElement {
  1: required i32 num,
}

struct stuff {
  1: optional map<i32,myElement> mymap,
}

Я получаю сгенерированный комиссионный класс с картой STL. Экземпляр этого класса долгоживущий (Я добавляю и удаляю его, а также записываю на диск с помощью TSimpleFileTransport).

Я хотел бы расширить myElement в C ++, расширения не должны влиять сериализованная версия этого объекта (и этот объект не используется ни в другой язык). Какой простой способ добиться этого?

Я размышлял о следующем, но они не казались чистыми:

  1. Создайте вторую нетривиальную карту, индексированную с тем же ключом
    • синхронизация обоих данных может оказаться болезненной
  2. Изменить сгенерированный код либо путем последующей обработки сгенерированного заголовок (включая взлом пропроцессора).
  3. Аналогично # 2, но измените сторону генерации, включив в сгенерированную структуру следующее, а затем определите NAME_CXX_EXT в принудительно включенном заголовке.
      #ifdef NAME_CXX_EXT
      NAME_CXX_EXT ...
      #endif
    

Все вышеперечисленное кажется довольно неприятным


Решение, с которым я собираюсь сейчас пойти:

[Это весь псевдокод, не проверял эту копию для компиляции]

Следующий сгенерированный код, который я не могу изменить (хотя я могу изменить карту на набор)

class GeneratedElement {
 public:
   // ...
   int32_t num;
   // ...
};


class GeneratedMap {
 public:
   // ...
   std::map<int32_t, GeneratedElement>  myGeneratedMap;
   // ...
};

// End of generated code

В другом месте приложения:

class Element {
 public:
   GeneratedElement* pGenerated; // <<== ptr into element of another std::map!
   time_t lastAccessTime;
};


class MapWrapper {
private:
  GeneratedMap theGenerated; 

 public:
   // ...
   std::map<int32_t, Element>  myMap;
   // ...

   void doStuffWIthBoth(int32_t key)
   {
     // instead of 
     //   theGenerated.myGeneratedMap[key].num++;  [lookup in map #1]
     //   time(&myMap[key].lastAccessTime);        [lookup in map #2]
     Element& el=myMap[key];
     el.pGenerated->num++;
     time(&el.lastAccessTime);
   }
};

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

Я полагал, что могу гарантировать, что все вставки и удаления в / из theGenerated) сделаны в одном месте, и в этом же месте я заполняю / удаляю соответствующую запись в myMap, я бы потом смог инициализировать Element :: pGenerated для соответствующего ему элемента в Generated.myGeneratedMap

Это не только позволит мне сэкономить половину времени поиска, я даже могу изменить myMap для лучшего типа контейнера для моего типа ключа (скажем, hash_map или даже повышение многоиндексная карта)

Сначала это звучало для меня как плохая идея. С помощью std :: vector и std :: dqueue я могу посмотрим, как это может быть проблемой, так как значения будут перемещаться, аннулирование указателей. Учитывая, что std :: map реализован с помощью дерева структура, есть ли время, когда элемент карты будет перемещен? (мои предположения были подтверждены обсуждением в введите описание ссылки здесь )

Хотя я, вероятно, не буду предоставлять метод доступа каждому члену myElement или любому синтаксическому сахару (например, перегрузке [] () и т. Д.), Это позволяет мне обрабатывать эти элементы почти согласованным образом. Единственный ключ в том, что (кроме вставки) я никогда не ищу членов mymap напрямую.

1 Ответ

0 голосов
/ 02 августа 2011

Рассматривали ли вы просто использование простого контейнеровоза?

Вы используете C ++, поэтому вы можете просто обернуть struct (s) в некоторый класс или другую структуру и предоставить методы-обертки, чтобы делать все, что вы хотите.

...