4

私はフラグと呼んでいるJavaスタイルのEnumのようなものを作ろうとしています。要件は、各フラグが静的であるため、フラグが直接参照可能であり、各フラグがその名前の文字列を格納し、セット全体が反復可能でルックアップを助長することです。

フラグの各セットが個別に格納されるようにテンプレートを使用しています (したがって、各子クラスにセットを明示的に配置する必要がなくなります)。

プログラムの実行の成功または失敗は、フラグ宣言を含むオブジェクト ファイルのファイル名に依存するため、これは初期化の問題であると確信しています (Ao は segfaults ですが、Zo は正常に動作します)。

問題は静的な初期化順序の 1 つにあるようです。このコードは完全に正常にコンパイルされますが、実行すると 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

アイテム.hpp

    class ItemFlag: public Flag<ItemFlag>
{
public:

    static const ItemFlag brick;

private:

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

アイテム.cpp

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

初めての投稿なので、書式設定が間違っていたり、具体的でない場合はお知らせください。PS。不思議なことに、set を vector に置き換えると、set が特にポインターの挿入に問題があるかのように、動作するプログラムが得られます。これをテストするために、セットを int のセットに置き換え、クラスの初期化時に 0 を挿入しようとしましたが、これも同じエラーが発生しました。

4

3 に答える 3

5

それは非常に簡単に初期化の問題の順序である可能性があります。基本的に、セットに対してある種の遅延初期化を使用する必要があります。

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

静的変数の代わりに。

とはいえ、これはおそらくテンプレートの適切な使い方ではありません。はるかに優れた解決策は、次の行に沿った、はるかに単純な形式のファイルからコードを生成することです。

[EnumName]
constant_name_1
constant_name_2

これを解析して C++ ヘッダーと C++ ソース ファイルの両方を出力するには、AWK、Perl、または Python (好みに応じて) で約 10 行しかかからないでしょう。その後、単純な書式を維持するだけで済みます。

于 2011-05-09T14:07:26.373 に答える
0

クラスのコンストラクターがアイテムを静的セットに挿入する場合、そのデストラクタはそれらを削除する必要があります。おそらく、コピー コンストラクターと代入演算子も必要です。aso、スタイルの観点から、保護されたデータは通常、悪いことと見なされます。

于 2011-05-09T13:59:27.837 に答える