2013-01-23 12 views
5

私は一時ファイルについて理解しているので、次のコードはうまくいくはずですが、そうではありません。C++ temporary - "純粋仮想メソッド"と呼ばれる

struct base 
{ 
    virtual~base() {} 
    virtual void virt()const=0; 
}; 
struct derived:public base 
{ 
    virtual void virt()const {} 
}; 

const base& foo() {return derived();} 

int main() 
{ 
    foo().virt(); 
    return 0; 
} 

virt()を呼び出すと、「純粋仮想関数が呼び出されました」というエラーが返されます。それはなぜですか、私は何をすべきですか?

答えて

5

constの参照で一時的なライフタイムが延長されると思われます。これが起こらない特定の状況があります。これらの状況の1つは、一時的なものを返すときです。

[一時表現が完全表現の終わりとは異なる位置で破壊される]第2のコンテキストは、参照が一時的にバインドされている場合です。

  • [...]

    :一時的に参照がバインドされたか、参照を除いて、参照の存続期間を通じて持続をバインドされているサブオブジェクトの完全なオブジェクトであることを、一時的であるに関数のreturn文(6.6.3)で返された値に一時的にバインドされた有効期間は延長されません。 return文の完全式の終わりに一時は破棄されます。

(タイプbase由来ではない)、あなたは未定義の動作を取得左辺値ツー右辺値の変換を必要とし、オブジェクトが無効であるだろうfoo()によって返されるオブジェクトのメンバ関数を呼び出して以来:

glvalueが参照するオブジェクトがタイプTのオブジェクトでなく、Tから派生したタイプのオブジェクトでない場合、またはオブジェクトが初期化されていない場合、この変換を必要とするプログラムは未定義の動作をします。

8

の末尾に関数 が終了し、未定義の動作が発生すると、破棄された一時的な参照が返されます。

一時的な参照を返すことはできません。baseを値で返すとスライスされるので、実際にこれを機能させたい場合は、std::unique_ptr<base>を返す必要があります。

+0

仮想テーブルも同様にクリーンアップされるため、正確にはメッセージです。 –

+2

@DougT .:「未定義の動作」に「理由がありません」はありません。 (それ以外は、仮想テーブル*は決して "クリーンアップ"されません) –

+0

virt()が返された後に、完全表現の終わりに一時オブジェクトが破棄されるべきではありませんか? – Dave

3

このようなオブジェクトへの参照を返すことはできません。 derived()インスタンスは、foo()が戻るとすぐに有効範囲外になります。動作するはず

base *foo() { return new derived(); } 

foo()->virt(); 

を持っています。

+3

これはうまくいくはずですが、最近では生ポインタを渡す必要はありません... –

+2

shared_ptr <>などを使用したい場合は、実際のコードで行うべきことです。しかし私の要点は、基本的には、ヒープ上にオブジェクトを配置して、これを動作させる必要があることです。ポインタを恐怖の隠蔽の下で隠すのはなぜですか? – Johannes

+1

@Johannes:それは単にメモリリークを求めているからです。スマートポインタは標準ライブラリにあります - それらを使用してください! : - ] – ildjarn

0

呼び出し中にオブジェクトが存在しないため、ローカルオブジェクトが削除されました。見るべきvtableはありません。試してください:

base& foo() { return *new derived(); } 
+0

発信者はメモリを解放する必要があることをどのようにして知っていますか? –

0

一時的な 'derived()'オブジェクトがスタックに割り当てられます。オブジェクトアップキャストとは何か関係があります。

const base & foo(){derived * d = new derived(); return * d; }

うまく動作します。

+1

メモリがリークしていてもうまく動作していません。 ; - ] – ildjarn

+0

本当にありがとう。 boost :: shared_ptr <> – Arcturus

0

変更し、これに問題ピース:

class A { 
public: 
    const base &foo() { return d; } 
private: 
    derived d; 
}; 

この方法で導出されたオブジェクトの有効期間は、Aの寿命と同じくらいの長さで、何の問題があることはありません。

+0

関数 'bar'のスタックにAを構築し、' bar'から 'd'への参照を返したらどうなりますか? –

関連する問題