3

次のクラスは厳密なエイリアシング ルールを破ります。

template<typename T>
class store {
    char m_data[sizeof(T)];
    bool m_init;
public:
    store() : m_init(false) {}
    store(const T &t) : init(true) {
        new(m_data) T(t);
    }
    ~store() {
        if(m_init) {
            get()->~T();
        }
    }
    store &operator=(const store &s) {
        if(m_init) {
            get()->~T();
        }
        if(s.m_init) {
            new(m_data) T(*s.get());
        }
        m_init = s.m_init;
    }
    T *get() {
        if (m_init) {
            return reinterpret_cast<T *>(m_data);
        } else {
            return NULL;
        }
    }
}

私の標準の読みは、それが正しくないということですが、よくわかりません (私の使用法は、オブジェクトの配列T+ それらのオブジェクトのいくつかのメタデータを持ちますが、メモリを手動で割り当てずにオブジェクトの構築/分解を制御することです)。標準での配置の例として使用されnewます。

4

2 に答える 2

4

規格には次の注記が含まれています。

[注:典型的な実装では、aligned_storage を次のように定義します。

template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
  typedef struct {
    alignas(Alignment) unsigned char __data[Len];
  } type;
};

エンドノート]

                                                                   — ポインターの変更 [meta.trans.ptr] 20.9.7.5/1

また、aligned_storage の一部は次のように定義されています。

メンバーの typedef型は、サイズが最大Lenで、アラインメントがAlignの約数であるオブジェクトの初期化されていないストレージとして使用するのに適した POD 型でなければなりません。

オブジェクトを構築できるアドレスを制限する標準でカバーされている唯一のプロパティは、アラインメントです。実装には他にもいくつかの制限があるかもしれませんが、私はそれについてよく知りません。したがって、実装で正しいアライメントがあれば十分であることを確認してください。これで問題ないと思います。(また、C++11 より前のコンパイラでは、コンパイラ拡張機能を使用して、__attribute__((alignment(X)))またはなどのアラインメントを設定できます__declspec(align(X))

基礎となるストレージに直接アクセスしない限り、エイリアシング ルールが問題になることさえないと思います。なぜなら、エイリアシング ルールは、異なるタイプのオブジェクトを介してオブジェクトの値にアクセスしてもよい場合をカバーするからです。 . オブジェクトを構築してそのオブジェクトのみにアクセスすることは、他の型のオブジェクトを介してオブジェクトの値にアクセスすることを伴いません。

以前の回答

エイリアシング ルールは、特に char 配列が他のオブジェクトにエイリアスを設定できるようにします。

プログラムが、次の型以外の glvalue を介してオブジェクトの格納された値にアクセスしようとした場合、動作は未定義です。

[...]

— char または unsigned char 型。

                                                                   — 左辺値と右辺値 [basic.lval] 3.10/10

ただし、配列が T 型に対して適切に配置されていることを確認する必要があります。

alignas(T) char m_data[sizeof(T)];

上記はアラインメントを設定するための C++11 構文ですが、C++03 コンパイラを使用している場合は、同じことを行うためにコンパイラ固有の属性が必要になります。GCC__attribute__((aligned(32)))と MSVC には__declspec(align(32))


Kerrek SB は、エイリアシング ルールが char 配列を介して T オブジェクトの値にアクセスしても問題ないと述べていることを指摘していますが、それは T オブジェクトを介して char 配列の値にアクセスしても問題ないという意味ではない可能性があります。ただし、配置の新しい式が適切に定義されている場合、定義により T オブジェクトとしてアクセスしても問題ないと思われる T オブジェクトが作成され、元の char 配列を読み取ると、作成された T オブジェクトの値にアクセスします。エイリアシング規則。

これは、たとえば int 配列に T オブジェクトを格納できることを意味していると思います。元の int 配列を介してその T オブジェクトの値にアクセスしない限り、未定義の動作は発生しません。

于 2012-06-09T23:38:04.483 に答える
0

許可されているのは、Tオブジェクトを取得して文字の配列として解釈することです。ただし、一般に、任意の char 配列を取り、それを として扱うこと、または を含むメモリ領域へのポインタとして扱うことは許可されていません。少なくとも、char 配列を適切に配置する必要があります。TT

これを回避する1つの方法は、ユニオンを使用することです。

union storage { char buf[sizeof(T)]; T dummy; };

Tこれでinsideを構築できますstorage.buf:

T * p = ::new (storage.buf) T();
于 2012-06-09T23:40:35.740 に答える