8

厳密なポインタエイリアシングルールに違反したために問題が発生しました。Tテンプレートからの型Intと、同じサイズの整数型があります(と同様)sizeof。私のコードは基本的に次のことを行います。

T x = some_other_t;
if (*reinterpret_cast <Int*> (&x) == 0)
  ...

Tコンストラクターを持つことができる任意の(サイズ制限以外の)型であるため、との和集合を作成することはできませTInt。(これはC ++ 0xでのみ許可されており、GCCではまだサポートされていません)。

機能を維持し、厳密なエイリアシングルールに違反しないように上記の擬似コードを書き直す方法はありますか?これはテンプレートであることに注意してください。制御しTたり、値を設定したりすることはできませんsome_other_t。割り当てとその後の比較は、テンプレート化されたコード内で行われます。

T(ちなみに、ビットフィールドが含まれている場合、上記のコードはGCC 4.5で壊れ始めました。)

4

5 に答える 5

1

聞いたことがありboost::optionalますか?

ここでの実際の問題については不明であることを認めなければなりません...しかし、boost :: optionは値で保存でき、実際のメモリが初期化されているかどうかを知ることができます。私はその場での建設と破壊も許可しているので、私が推測するのにぴったりかもしれません。

編集

私はついに問題を理解したと思います。メモリ内のさまざまなポイントに多くのオブジェクトを割り当てられるようにし、この時点でのメモリが本当にオブジェクトを保持しているかどうかを知りたいのです。

残念ながら、ソリューションには大きな問題があります。それは正しくありません。Tどういうわけかビットパターンで表すことができればnull、それはユニタライズされたメモリだと思うでしょう。

少なくとも1ビットの情報を追加するために自分自身に頼る必要があります。それほど多くはありませんが、結局のところ、それは成長の3%にすぎません(4バイトで33ビット)。

たとえば、いくつかのミミックboost::optionalを配列形式で使用できます(パディングの損失を回避するため)。

template <class T, size_t N>
class OptionalArray
{
public:


private:
  typedef unsigned char byte;

  byte mIndex[N/8+1];
  byte mData[sizeof(T)*N]; // note: alignment not considered
};

次に、それはそれと同じくらい簡単です:

template <class T, size_t N>
bool OptionalArray<T,N>::null(size_t const i) const
{
  return mIndex[i/8] & (1 << (i%8));
}

template <class T, size_t N>
T& OptionalArray<T,N>::operator[](size_t const i)
{
  assert(!this->null(i));
  return *reinterpret_cast<T*>(mData[sizeof(T)*i]);
}

:わかりやすくするために、配置の問題については考慮していません。あなたが主題について知らないならば、記憶をいじる前にそれについて読んでください:)

于 2010-06-05T16:30:37.807 に答える
1

33ビットコンピュータを使用してください。;-P

于 2010-06-05T18:12:05.523 に答える
1
static inline int is_T_0(const T *ob)
{
        int p;
        memcpy(&p, ob, sizeof(int));
        return p == 0;
}

void myfunc(void)
{
    T x = some_other_t;
    if (is_T_0(&x))
        ...

私のシステムでは、GCCはとの両方is_T_0()を最適化するためmemcpy()、でいくつかの組み立て手順が実行されmyfunc()ます。

于 2010-06-05T21:44:53.083 に答える
1

なぜ単純ではないのですか?

const Int zero = 0;
if (memcmp(&some_other_t, &zero, sizeof(zero)) == 0)
  /* some_other_t is 0 */

static(修飾子も追加しzeroて、パフォーマンスに違いがあるかどうかを確認することをお勧めします)

于 2012-07-15T07:14:24.560 に答える
0

これはどう:

Int zero = 0;
T x = some_other_t;
if (std::memcmp(&x, &zero, sizeof(zero)) == 0)

それほど効率的ではないかもしれませんが、警告を取り除く必要があります。


補遺#1:

Tはと同じサイズに制約されているため、Intタイプのダミーのビット単位のゼロ値を作成し、それとT直接比較します(agaistをキャストして比較するのではなくInt(0))。

プログラムがシングルスレッドの場合、次のようになります。

template <typename T>
class Container
{
public:
    void foo(T val)
    {
        if (zero_ == val)
        {
            // Do something
        }
    }

private:
    struct Zero
    {
        Zero() {memset(&val, 0, sizeof(val));}
        bool operator==(const T& rhs) const {return val == rhs;}
        T val;
    };
    static Zero zero_;
};

マルチスレッドの場合は、静的メンバーの使用を避け、zero_各コンテナーインスタンスに独自のzero_メンバーを保持させる必要があります。

template <typename T>
class MTContainer
{
public:
    MTContainer() {memset(zero_, 0, sizeof(zero_));}

    void foo(T val)
    {
        if (val == zero_)
        {
            // Do something
        }
    }

private:
    T zero_;
};

補遺#2:

上記の補遺を別のより簡単な方法で説明します。

// zero is a member variable and is inialized in the container's constructor
T zero;
std::memset(&zero, 0, sizeof(zero));

T x = some_other_t;
if (x == zero)
于 2010-06-05T15:48:46.350 に答える