1
  • 次のコードには定義済みの動作がありますか?
  • そうでない場合、コードのどの部分が UB であり、標準のどのセクションが UB であるか?
  • このコードが UB の場合、それを修正できる [小さな] 変更はありますか?
  • 何も修正できない場合、同じ機能を実装するために使用できる他のコードスキーム/パターンは何ですか?

class C
{
public:
    virtual ~C() {}
    virtual void switch_me() = 0;
};

class C1 : public C
{
public:
    C1() : b(true)      { std::cout << "C1\n"; }
    ~C1()               { std::cout << "~C1\n"; }
private:
    void switch_me();
    bool b;
};

class C2 : public C
{
public:
    C2() : i(1)         { std::cout << "C2\n"; }
    ~C2()               { std::cout << "~C2\n"; }
private:
    void switch_me();
    int  i;
};

void C1::switch_me()
{
    this->~C1();            // lifetime of *this ends here
    std::cout << "blih\n";  // execute some code that does
                            // not attempt to access object
    new(this) C2();         // create a C2 instance in-place
}

void C2::switch_me()
{
    this->~C2();            // lifetime of *this ends here
    std::cout << "blah\n";  // execute some code...
    new(this) C1();         // create a C1 instance in-place
}

class Cnt
{
public:
    Cnt()           { new(&storage) C1(); }
    ~Cnt()          { (*this)->~C(); }
    C* operator->() { return reinterpret_cast<C*>(&storage); }
private:
    char storage[std::max(sizeof(C1),sizeof(C2))];
};

int main()
{
    Cnt c;
    c->switch_me();
    c->switch_me();
    return 0;
}
4

1 に答える 1

3

関数に関して未定義の動作はありませswitch_meん。破棄後にオブジェクトにアクセスせず、次のアクセスは新しいオブジェクトで発生します。Cポインタとオブジェクトへの参照を保存して vy を返し、それをper 3.8/7operator->の呼び出し後に使用すると、UB が発生する可能性があります。switch_me

オブジェクトの有効期間が終了した後、オブジェクトが占有していたストレージが再利用または解放される前に、元のオブジェクトが占有していたストレージの場所に新しいオブジェクトが作成された場合、元のオブジェクトを指すポインタ、その参照または、元のオブジェクトの名前が自動的に新しいオブジェクトを参照し、新しいオブジェクトの有効期間が開始されると、新しいオブジェクトを操作するために使用できます。

  • 新しいオブジェクトのストレージは、元のオブジェクトが占めていたストレージの場所を正確にオーバーレイします。
  • 新しいオブジェクトが元のオブジェクトと同じ型である (最上位の cv 修飾子を無視する)、および
  • 元のオブジェクトの型が const 修飾されておらず、クラス型の場合は、型が const 修飾されているか参照型である非静的データ メンバーが含まれていない。
  • 元のオブジェクトは型 T の最派生オブジェクト (1.8) であり、新しいオブジェクトは型 T の最派生オブジェクトです (つまり、それらは基本クラスのサブオブジェクトではありません)。

他の場所、つまりストレージに UB があります。配置したいオブジェクトよりも位置合わせが弱いため、位置合わせの問題が発生する可能性があります。alignasキーワードを使用して、目的の配置を指定します。

alignas(C1) alignas(C2) char storage[std::max(sizeof(C1),sizeof(C2))];

2 つの配置指定子が同じ宣言に適用される場合、大きい方が使用されます。

于 2016-06-11T09:54:45.547 に答える