std :: set используется как статическая переменная-член - PullRequest
4 голосов
/ 09 мая 2011

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

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

Я убежден, что это проблема инициации, поскольку успех или неудача запуска программы зависит от имени файла объектного файла, которыйсодержит объявления флагов (Ao segfaults, но Zo работает нормально.)

Проблема, похоже, связана со статическим порядком инициализации, этот код прекрасно компилируется, но при запуске gdb выдает следующее:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff751e0fa in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/libstdc++.so.6
(gdb) bt
#0  0x00007ffff751e0fa in std::_Rb_tree_decrement(std::_Rb_tree_node_base*) ()
from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/libstdc++.so.6
#1  0x0000000000462669 in operator-- ()
at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_tree.h:199
#2  _M_insert_unique ()
at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_tree.h:1179
#3  insert () at /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_set.h:411
#4  Flag () at include/../util/include/Flag.hpp:34
#5  ItemFlag () at include/Item.hpp:22
#6  __static_initialization_and_destruction_0 () at Item.cpp:15
#7  global constructors keyed to _ZN3code8ItemFlag5brickE() () at Item.cpp:86
#8  0x000000000046ac62 in ?? ()
#9  0x00007fffffffddc0 in ?? ()
#10 0x000000000046abb0 in ?? ()
#11 0x0000000000692c0a in ?? ()
#12 0x0000000000407693 in _init ()
#13 0x00007ffff7dded08 in ?? () from /usr/lib64/libboost_serialization-1_42.so.1.42.0
#14 0x000000000046abe7 in __libc_csu_init ()
#15 0x00007ffff6cd9b50 in __libc_start_main () from /lib64/libc.so.6
#16 0x0000000000408329 in _start ()

Мой код выглядит следующим образом:

template <class FlagType> class Flag
{
public:

    Flag(int ordinal, String name):
    ordinal(ordinal),
    name(name)
    {
        flagSet.insert(this);
    }

    inline bool operator==(const Flag<FlagType>& e) const
    {
                    //edited due to comment
        //if(this->ordinal == e.getOrdinal()) return true;
        //else return false;
                    return (this->ordinal == e.getOrdinal());

    }

    inline bool operator!=(const Flag<FlagType>& e) const
    {
        return !(*this==e);
    }

    static const std::set<const Flag<FlagType>*>& flagValues()
    {
        return flagSet;
    }

    const String& toString() const
    {
        return name;
    }

    const size_t& getOrdinal() const
    {
        return ordinal;
    }

    static int size()
    {
        return flagSet.size();
    }

    static const Flag<FlagType>& valueOf(const String& string)
    {
        typename std::set<const Flag<FlagType>*>::const_iterator i;
        for(i = flagSet.begin(); i != flagSet.end(); i++)
        {
            if((**i).toString().startsWith(string))
            {
                return **i;
            }
        }
        throw NotAFlagException();
    }

protected:

    static std::set<const Flag<FlagType>*> flagSet;

    size_t ordinal;
    String name;
    private:
            //added in response to comment to prevent copy and assignment, not compile tested
            Flag<FlagType>(const Flag<FlagType>&);
            Flag<FlagType>& operator=(const Flag<FlagType>&);
};

template <class FlagType> std::set<const Flag<FlagType>*> Flag<FlagType>::flagSet; //template

Item.hpp

    class ItemFlag: public Flag<ItemFlag>
{
public:

    static const ItemFlag brick;

private:

    ItemFlag(int ordinal, String name):
    Flag<ItemFlag>(ordinal, name){}
};

Item.cpp

const ItemFlag ItemFlag::brick(1, "brick");

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

Ответы [ 3 ]

5 голосов
/ 09 мая 2011

Это очень легко может быть проблема порядка инициализации. Вы в основном нужно использовать какую-то ленивую инициализацию для набора, например

static std::set<Flag<FlagType> const*>& flagSet()
{
    static std::set<Flag<FlagType> const*> theOneAndOnly;
    return theOneAndOnly;
}

вместо вашей статической переменной.

И пока я на это: это, вероятно, не хорошее использование шаблонов. Гораздо лучшим решением было бы сгенерировать код из файла с гораздо более простой формат, примерно такой:

[EnumName]
constant_name_1
constant_name_2

и т.д.. Вероятно, потребуется не более 10 строк AWK, Perl или Python (в соответствии с вашими вкусами), чтобы проанализировать это и вывести как C ++ заголовок и исходный файл C ++ для него. Вам остается только поддерживать простой формат.

0 голосов
/ 09 мая 2011

Порядок статической инициализации между различными единицами перевода не гарантируется.Из дампа кажется, что ItemFlag созданы до того, как набор будет создан.Это делает вставку неудачной.

Изменение имени файла просто может повлиять на порядок файла в процессе компоновки.Это объясняет, почему файл, начинающийся с буквы A, связан с ранними версиями.

Единственный способ правильно выполнить эту работу - это задать набор и ItemFlag s в одном файле .cpp.Тогда порядок всегда сверху вниз.Если они находятся в разных файлах, компоновщик решает порядок (в основном наугад).

0 голосов
/ 09 мая 2011

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

...