2016-10-09 6 views
1
#include <iostream> 
#include <typeinfo> 
struct A { int a; }; 
struct B : virtual A { int b; }; 
struct C : virtual A { int c; }; 
struct D : B,C { int d; }; 
int main() 
{ 
    D complete; 
    B contiguous; 
    B & separate = complete; 
    B * p[2] = {&separate, &contiguous}; 
    // two possible layouts for B: 
    std::cout<< (int)((char*)(void*) &p[0]->a -(char*)(void*)&p[0]->b)<<" "<< sizeof(*p[0])<< "\n"; 
    std::cout<< (int)((char*)(void*) &p[1]->a -(char*)(void*)&p[1]->b)<<" "<< sizeof(*p[1])<< "\n"; 

    alignas(B) char buff[sizeof(B)]; 
    void * storage = static_cast<void*>(buff); 
    // new expression skips allocation function: 
    auto pointer= new (storage) B;  // Which layout to create? 
    std::cout << typeid(pointer).name()<<"\n"; 
    pointer->~B(); // Destructor knows layout through typed pointer. 
} 
// sample output (Debian 8, amd64): 
// 24 16 
// 4 16 
// P1B 

C++ 14標準には、特定のレイアウトを作成するために「新規」が必要なセクションはありますか? サイズがsizeof(B)で、オフセットがゼロのバッファに新しいフィットで作成されたレイアウトが保証されていますか?プレースメントはどのレイアウトを作成するのかを知っていますか?


編集:grep-friendly用語を使用していただくか、参考にしてください。標準への言及を質問に追加しました。

上記のサンプル出力を考慮してください:番号24とは何ですか?バッファのサイズは?

ほとんどの派生オブジェクトは常にオブジェクト表現の直接的な連続コピーであるという文が標準であるかもしれませんが、 が見つかりませんでした。

私たちが新しく知っていることは、完全なオブジェクトタイプで使用されることです。 [expr.new]

[class.dtor]§12.4(14)の配置オプションを使ったnew-expressionの例があります。しかし、そのクラスが標準レイアウトであるため、この例は単純に機能するかもしれません。

答えて

2
引数があるとして、サイズはsizeof(B)のバッファに新しいフィットで作成したレイアウトとではタイプが newで命名されていることから、ゼロ

オフセットが保証されて

BDではなく、Bが作成されています。タイプBは「知らない」約Dです。 Dの宣言はBに影響しません。 B宣言は、Dが表示されない翻訳単位に入れることができますが、プログラム内のどこでもBのサイズについて合意があり、その場所でもDが知られているかどうかにかかわらず、レイアウトです。

タイプTのC++オブジェクトのサイズは、sizeof Tです。これは、sizeof Tバイトに収まることを意味します。その表現には(sizeof T) + kバイトが必要な場合はありません。ここでは、k > 0です。

+0

「k!= 0」ではないはずですか? –

+0

@AlexisWilkeもし 'k'が' signed int'で負であれば、それが 'size_t'に追加されるとどうなりますか? :) – Kaz

+0

私は確信していません...あなたは教えてください。しかし、おそらく私はそれが 'k> = 0'ではなく' k> = 0'でなければならないと言います。あなたは答えを書きました... –

1

派生型を作成する以外に、「別の」レイアウトと呼ばれるものを作成するオプションはありません。そのうちの1つとしてBを釣り上げることはできません。

"Bの派生クラスの一部としてのレイアウト"は、 "レイアウトがB"と同じではありません。プレースメントnewと通常のnewは、タイプ自体に基づいてレイアウトを使用します。デフォルトは、スタンドアロンのデフォルトのレイアウトです。

新しいデザインで作成されたレイアウトが、サイズがsizeof(B)のバッファに収まることは保証できますか?

sizeof(B)ないB -as-部分の-一部、他のクラス、Bの大きさ自体を返します。これは、メモリを割り当てる方法にかかわらず、独立型のBを格納するために必要なすべての領域です。

0

二つの新しい表現で起こっものがあります(ない 新しい表現ではありません)new演算子所望のタイプの

  • 建設を呼び出すことにより、タイプのためにメモリを割り当てる

    1. が。

    通常、new演算子は、新しい式の中でコンパイラによって渡されるサイズを利用することができます。新しいプレースメント(ストレージを提供する)を持つことにより、プログラマは、望ましいタイプを保持するのに十分な大きさのストレージを提供する責任があります。

    とにかく:割り当てとオブジェクトの構成を混在させないでください。これらは2つの異なるタスクです。

  • 0

    精度:仮想継承を実装する方法は、すべての独自のメンバーフィールド宣言の後にクラスの最後に仮想基本クラスをプッシュすることです。ここで、クラスD、クラスBの組織でなければならない

    class D: 
        ----- 
        pvmt for B, D (include shift to find A) 
        int b; 
        ----- 
        pvmt for C (include shift to find A) 
        int c; 
        ----- 
        int a; 
        ----- 
    
    class B: 
        ----- 
        pvmt for B (include shift to find A) 
        int b; 
        ----- 
        int a; 
        ----- 
    
    class C: 
        ----- 
        pvmt for C (include shift to find A) 
        int c; 
        ----- 
        int a; 
        ----- 
    

    void* rawObject= new (storage) B;のレイアウトを選択newありません。具体的なBオブジェクトを作成するのは事実です。したがって、レイアウトはcontiguousのものと同じです - 第2のもの。

    関連する問題