2010-03-31 2 views
3

У меня есть универсальный тип данных, который передается по значению, но не поддерживает информацию о типе. Мы храним только указатели и основные типы данных (например, int, float и т. Д.). Теперь в первый раз нам нужно сохранить std :: string внутри этого. Поэтому мы решили преобразовать его в std :: string * и сохранить его. Затем возникает проблема разрушения. Нам не нравится копировать std :: string каждый раз. Поэтому я думаю о таком подходе. Скажем, тип данных выглядит следующим образомC++ универсальный тип данных

class Atom 
{ 
public : 
    enum flags 
    { 
     IS_STRING, 
     IS_EMPTY, 
     HAS_GOT_COPIED, 

     MARKER 
    }; 

private: 
    void* m_value; 
    std::bitset<MARKER> m_flags; 

public: 
    ..... 
    Atom(Atom& atm) 
    { 
     atm.m_flags.set(HAS_GOT_COPIED); 
     ..... 
    } 
    ..... 
    ~Atom() 
    { 
     if(m_flags.test(IS_STRING) && !m_flags.test(HAS_GOT_COPIED)) 
     { 
      std::string* val = static_cast<std::string*>(m_value); 
      delete val; 
     } 
    } 
}; 

Это хороший подход, чтобы выяснить, нет ли больше нет ссылок на StD :: строка *? Любые комментарии ..

Я посмотрел boost :: any и poco :: DynamicAny. Поскольку мне нужна сериализация, я не могу их использовать.

Thanks, Gokul.

+1

Вы посмотрели на boost :: variant? Как сериализация влияет на использование boost :: any? (Я никогда не пробовал poco :: DynamicAny) –

+1

Почему не шаблон Atom на тип объекта, который он будет содержать? –

+0

@George: Это не будет один тип данных, и это не будет служить цели. – Gokul

ответ

4

Одним из основных недостатков этого подхода является то, что вы действительно нужен счетчик ссылок, а не один бит «был скопирован». Бит не будет работать, если вы скопируете строку несколько раз. Как написано, вы получите в беду, если вы создаете копию Atom и удалить копию, прежде чем оригинал:

Atom a("hello world"); 

if (...) { 
    Atom b(a); 
    // b is destroyed, deleting the string 
} 

// Uh oh, the string's been deleted but a is still referencing it. 
cout << (string) a; 

я бы не изобретать колесо. Если boost::any не работает из коробки, вы все равно можете использовать его внутри своего поля m_value для хранения данных для вашего класса Atom. Это позаботится обо всех деталях строительства/копирования/уничтожения для вас.

+0

Спасибо .. У меня проблема. Но я не могу использовать boost :: any, потому что он не поддерживает boost serialization. – Gokul

+1

. Вы можете добавить сериализацию в свой класс (как вы это делаете сейчас) и использовать внутренне либо boost :: any, либо boost :: variant –

+0

@David : Я не хочу платить стоимость boost :: any, если я не могу сохранить type_info (путем преобразования всего в void *, а затем вставки внутри boost :: any). В настоящее время я сериализую, беря данные как поток байтов с длиной. – Gokul

4

Я думаю, вы должны изучить возможность использования boost :: shared_ptr (или std :: tr1 :: shared_ptr).

+0

Это тип данных типа pass by value. Я думаю, что ваше предложение действительно для прохода по эталонному типу данных. – Gokul

+0

Его предложение подходит для класса с перекрестными знаками. Очевидно, что тип копирования без ссылки на копирование не имеет проблем с копированием. –

+1

Я хотел использовать shared_ptr для отслеживания std :: string * и освобождения в нужный момент. Как ваш код обрабатывает случай, когда Atom, содержащий std :: string, был скопирован несколько раз, а исходный экземпляр имеет самый длинный срок службы? –

3

Возможно, вам захочется подавать «копию на запись» в Google и читать по этой теме. Как это обычно реализуется, для чего он используется и каковы его недостатки.

И вы посмотрели boost::any?

+0

Да, я смотрел на boost :: any. Его нельзя использовать здесь, потому что нам нужна сериализация этого. – Gokul

+0

@Gokul: Это не похоже на то, что ваш тип будет поставляться с сериализацией бесплатно - вам также придется реализовать это самостоятельно. Если вы основываетесь на 'boost: any', по крайней мере, у вас прочный фундамент. – sbi

1

Помимо того, является ли этот тип универсальных данных хорошей идеей, если вы не копируете строку, может ли этот класс быть уверенным, что он владеет строкой, на которой указатель? Можете ли вы гарантировать, что только строки, выделенные через new, будут переданы классу, чтобы получить право собственности?

Дизайн этого класса выглядит так, как будто это будет проблематично.

+0

Да, у меня будет только этот конструктор и нет set-statements. – Gokul

+0

@Gokul - это не проблема. Можете ли вы быть уверены, что тот, кто вызывает конструктор, сделает это только со строкой, которая была назначена через 'new', и что вызывающий абонент не будет впоследствии вызывать' delete' в строке? Это правила, которые трудно выполнить с вашим дизайном, поэтому было бы неплохо подумать о них, прежде чем приступать к такому дизайну. –

+0

Извините, я не упоминал об этом, но люди будут передавать его только как std :: string, и я преобразую его в std :: string * внутри этого. Поэтому мне нужно освободить его. Если он передан как std :: string *, то это не будет беспокоиться о его освобождении. – Gokul

2

Одна из моих первых задач на моей первой работе заключалась в разработке варианта класса. Вы можете найти базовый код (и обсуждение) здесь в этом comp.lang.c++.moderated post.

Поскольку вам также нужна сериализация, вам может быть интересна библиотека JsonCpp. Я думаю, что он предлагает только то, что вы ищете: тип данных, который может быть строкой, bool, int, array, object и т. Д. (Json::Value класс.)

+0

Спасибо! Я это проверю. – Gokul

+0

Незнакомец, объясните, когда вы будете downvoting :) – StackedCrooked

Смежные вопросы