23

g++ 4.7 と vs2012 (cl17) で異なる出力を生成するコードを次に示します。

#include <iostream>

using namespace std;

class A
{
public:
    A() { cout << "1" << endl; }
    ~A() { cout << "2" << endl; }
};

class B : public A
{
public:
    B() { cout << "3" << endl; }
    ~B() { cout << "4" << endl; }
};

void func(A a) {}

int main()
{
    B b;
    func(b);
    return 0;
}

GCC の出力は ですが13242、cl の出力は132242です。

cl コンパイラがスタックにコピーを作成しているときに 2 番目のオブジェクトを生成するのはなぜAですか? また、その目的は何ですか?

4

3 に答える 3

5

コンパイラのバグのようです。C++ 標準では、オブジェクト スライシング
という用語は使用されません。タイプのオブジェクトを、タイプのパラメータを受け取る関数に渡します。コンパイラは、通常のオーバーロード解決を適用して、適切な一致を見つけます。この場合: 基本クラス には、コンパイラが提供するコピー コンストラクターがあり、他の変換関数への参照を取得し、他の変換関数がない場合、これが最適であり、コンパイラーによって使用される必要があります。BA
AA

より良い変換が利用できる場合は、それが使用されることに注意してください。例:コピー コンストラクターに加えてAコンストラクA::A( B const& )ターがある場合、コピー コンストラクターの代わりにこのコンストラクターが使用されます。

于 2012-11-14T08:40:45.280 に答える
0

C ++コンパイラは、次の状況でデフォルトのコピーコンストラクタを合成します。(C ++オブジェクトモデルの内部から)

  1. コピーコンストラクターが存在するクラスのメンバーオブジェクトがクラスに含まれている場合。
  2. コピーコンストラクタが存在する基本クラスからクラスが派生した場合。
  3. クラスが1つ以上の仮想関数を宣言するとき
  4. クラスが、1つ以上の基本クラスが仮想である継承チェーンから派生している場合。

クラスAが4つの状況にないことがわかります。したがって、clはデフォルトのコピーコンストラクタを合成しないでください。たぶんそれが2つのtempAオブジェクトが構築され破壊された理由です。

分解ウィンドウから、A::Aが呼び出されていない次のコードを確認できます。:

B b;
00B317F8  lea         ecx,[b]  
00B317FB  call        B::B (0B31650h)  
00B31800  mov         dword ptr [ebp-4],0  
func(b);
00B31807  mov         al,byte ptr [ebp-12h]  
00B3180A  mov         byte ptr [ebp-13h],al  
00B3180D  mov         byte ptr [ebp-4],1  
00B31811  movzx       ecx,byte ptr [ebp-13h]  
00B31815  push        ecx  
00B31816  call        func (0B31730h)  

しかし、デストラクタを仮想化するとします。次の逆アセンブルコードを取得します。A::Aが呼び出されていることがわかります。その後、結果は期待どおりになり、1つのオブジェクトのみが作成されます。

B b;
00331898  lea         ecx,[b]  
0033189B  call        B::B (03316A0h)  
003318A0  mov         dword ptr [ebp-4],0  
func(b);
003318A7  push        ecx  
003318A8  mov         ecx,esp  
003318AA  mov         dword ptr [ebp-1Ch],esp  
003318AD  lea         eax,[b]  
003318B0  push        eax  
003318B1  call        A::A (0331900h)  
003318B6  mov         dword ptr [ebp-20h],eax  
003318B9  call        func (03317D0h) 
于 2012-11-25T12:58:39.630 に答える
-3

コンパイラのバグに遭遇しました。

適切な機能を以下に説明します。


関数funcはオブジェクトのコピーを作成する必要があります (ただし、スライスに注意してください)。

それで、何が起こるかはこれです:

int main()
{
    // create object B, which first creates the base object A
    B b;
    // create object A, using this copy constructor : A( const B& )
    func(b);
}

追加の ~A() 呼び出しは、コピー構築されたオブジェクト A がfunc呼び出しの最後に破棄されるときに行われます。

于 2012-11-14T08:14:53.917 に答える