Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Ошибка при работе с boost::any
Форум на CrossPlatform.RU > Библиотеки > boost
AD
Почему-то вылетает с ошибкой при работе со следующим кодом:
void fillVectorTypes(std::vector<any>& types)
{
    DCW_HEAD type_1;            HEAD type_2;
    types.push_back(type_1);    types.push_back(type_2);
}

/// Инициализация заголовка карты и ее флагов
void CategoriesCharts::initMapEntity(const TabType key, MapEntity& entity)
{
    QFile file(entity.name());
    if(!file.open(QIODevice::ReadOnly)) return;
    qint64 sz = -1;
    std::vector<any> _types;
    fillVectorTypes(_types);
    file.read((char*)&_types[key], sizeof(_types[key]));
    file.close();
}


Правда, структуры не имеют конструкторов, но это код библиотеки:
struct DCW_HEAD
{
  char  title [16],
        File_name [8];
  float Latb, Late,
        Lonb, Lone,
        C0;
};

typedef unsigned char UByte;
typedef signed   char SByte;

struct HEAD
{
  char  title [TRS_TITLE_LEN],
        Corr_date [11],
        Chart_name [9],
        File_name  [9];
  float dlat, dlon,
        Latb, Late,
        Lonb, Lone,
        Latm, C0;
  short year_PD, month_PD,
        year_PP, month_PP,
        year_EC, month_EC;
  char  WGS;
  SByte  DP_mean,
        LH_dir,
        Datum,
        Proj,
        Type,
        Cntr,
        LangP,
        LangE,
        Reg,
        CntG,
        compress;

  SByte  WaterLevel,
        HO_mean,
        TypeEx;

  SByte  PubNum;
  SByte  CorrIssue;

  SByte  reserved [ 2 ];
  SByte  revision;
};


Отладчик выпадает на следующие строки:
~any()
        {
            delete content;
        }

Как можно исправить ошибку?
BRE
sizeof( any ) == 4, т.е. он хранит указатель на внутренний объект (content)!
Читая file.read((char*)&_types[key], sizeof(_types[key])) ты этот указатель затираешь первыми четырьмя байтами из файла. При разрушении any программа падает. Все логично. ;)
Обрати внимание на any_cast<Type>(...)!!!
AD
Цитата
sizeof( any ) == 4, т.е. он хранит указатель на внутренний объект (content)!
Читая file.read((char*)&_types[key], sizeof(_types[key])) ты этот указатель затираешь первыми четырьмя байтами из файла. При разрушении any программа падает. Все логично. ;)
Обрати внимание на any_cast<Type>(...)!!!

А как именно поправить я не понял? Прости, если донимаю...
BRE
Цитата(AD @ 10.8.2009, 9:12) *
А как именно поправить я не понял? Прости, если донимаю...

Примерно так:
void CategoriesCharts::initMapEntity(const TabType key, MapEntity& entity)
{
    QFile file(entity.name());
    if(!file.open(QIODevice::ReadOnly)) return;
    qint64 sz = -1;
    std::vector<any> _types;
    fillVectorTypes(_types);
    if( _types[ key ].type() == typeid( DCW_HEAD ) )
        file.read( (char*)&any_cast<DCW_HEAD>( _types[ key ] ), sizeof( any_cast<DCW_HEAD>( _types[key] ) ) );
    else if( _types[ key ].type() == typeid( HEAD ) )
        file.read( (char*)&any_cast<HEAD>( _types[ key ] ), sizeof( any_cast<HEAD>( _types[key] ) ) );
    file.close();
}
AD
Цитата(BRE @ 10.8.2009, 9:20) *
Примерно так:

Спасибо. А вопрос такой, а можно ли это сделать так, чтобы при добавлении, например, еще какого-то типа данных, ну например топографии другого формата, не надо было бы еще одну ветку else делать? Т.е. смысл-то этого вектора с any, чтобы он автоматом определял тип, а не при непосредственном приведении.
BRE
Цитата(AD @ 11.8.2009, 9:26) *
Цитата(BRE @ 10.8.2009, 9:20) *
Примерно так:

Спасибо. А вопрос такой, а можно ли это сделать так, чтобы при добавлении, например, еще какого-то типа данных, ну например топографии другого формата, не надо было бы еще одну ветку else делать? Т.е. смысл-то этого вектора с any, чтобы он автоматом определял тип, а не при непосредственном приведении.

Поэтому я тебе и написал, что не могу понять для чего ты все это делаешь. Теперь понял. ;)

IMHO any не очень подходит для таких задач. Можно попробовать получать имя типа из type_info, но все равно придется городить свой if для каждого типа. При добовлении нового типа, нужно будет дописывать свою ветвь.

Может лучше воспользоваться фабриками. Для каждого типа карты делается специальный класс loader, который умеет ее загружать. Все они регистрируются в фабрике и она создает объект-загрузчик в зависимости от указанного типа.
AD
Цитата(BRE @ 11.8.2009, 13:17) *
Поэтому я тебе и написал, что не могу понять для чего ты все это делаешь. Теперь понял. ;)

IMHO any не очень подходит для таких задач. Можно попробовать получать имя типа из type_info, но все равно придется городить свой if для каждого типа. При добовлении нового типа, нужно будет дописывать свою ветвь.

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

Об этом подумал. Какой класс буста использовать? :) Как приблизительно это можно реализовать? Спасибо за помощь!!!
BRE
Цитата(AD @ 11.8.2009, 13:22) *
Об этом подумал. Какой класс буста использовать? :) Как приблизительно это можно реализовать? Спасибо за помощь!!!

Мне понравилось одно решение с фабриками (подсмотрел на Inside C++). Я его немного переделал, что бы в качестве ключа можно было использовать не только строки.
Раскрывающийся текст

template <typename key, class base>
class factory
{
public:

    typedef boost::shared_ptr<base> base_ptr;

    template <class derived>
    void reg( const key& name )
    {
        factories[ name ] = base_type_ptr( new derived_type<derived> );
    }

    base_ptr create( const key& name )
    {
        if( !factories.count( name ) )
            throw std::out_of_range( "factory: key not found" );
        return factories[ name ]->create();
    }

private:

    class base_type
    {
    public:

        virtual ~base_type() {}

        virtual base_ptr create() const = 0;
    };

    typedef boost::shared_ptr<base_type> base_type_ptr;

    template <class T>
    class derived_type : public base_type
    {
    public:

        virtual base_ptr create() const
        {
            return base_ptr( new T );
        }
    };

    typedef std::map<key, base_type_ptr> factory_container;
    factory_container factories;
};



Как это использовать:
Раскрывающийся текст

// Виртуальный базовый класс
class Loader
{
public:
    virtual    bool load() = 0;
};

// Загружает карту земли
class EarthMapLoader : public Loader
{
public:
    virtual    bool load();
};

// Загружает карту моря
class SeaMapLoader : public Loader
{
public:
    virtual    bool load();
};

void func()
{
    typedef factory<int, Loader> LoaderFactory;
    typedef LoaderFactory::base_ptr LoaderPtr;

    LoaderFactory loaders;

    // Регистрируем загрузчики
    loaders.reg<EarthMapLoader>( 0 );
    loaders.reg<SeaMapLoader>( 1 );

    // Использование
    int index = 1;        // index тип карты
    
    // В зависимости от index создаем нужный объект загрузчика
    LoaderPtr loader = loaders.create( index );

    // loader - указывает на объект SeaMapLoader
    // Вызываем метод load
    loader->load();
}

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.