2017-01-04 20 views
1

私は現在、ファクトリ関数のパターンを実装できるようにするために、C++とcopy elision、特に「名前付き戻り値最適化」(NRVO)と苦労しています。異なるコンパイラ間で一貫した動作を得ることができません。注:virtual base-dtorを削除すると問題は解決しますが、実際の実装には必要です。強制的にコピーを削除しますか? gcc 5.4.1

デストラクタが呼び出されたGCC 5.4.0の場合は、何のコピーの省略が行われていない:

$ g++ test2.cpp && ./a.out 
start 
dtor derived 
dtor base 
done. should have leaked! 

のgcc 5.4.1を使用している場合(Ubuntuは5.4.1、それを呼び出し、私は、これはSVN-頭であると仮定)、私は様々な他のGCCの上だけでなく、私の手を得ることができ、すべてのclangsがエリジオンを実行し、正常にメモリリーク:私はinternetz間で異なる場所を読んで

$ g++ test2.cpp && ./a.out 
start 
done. should have leaked! 

、コンパイラはは、コピーを行うこと許可されていますelision(必須ではありません)。 C++ 17のみ保証付きコピーelisionを導入しています。これはgcc 5.4.0のバグですか、それとも単に標準を違う方法で実装しているのですか?

+7

コンパイラが最適化を許可されていても、それをする必要はありません。 – NathanOliver

+3

私は質問を編集し、gccの健全なコードについての部分を削除します - この部分は、とにかくofftopicになります。 – SergeyA

+0

「正常にリークしました」と言えば、GCCにもメモリが漏れていることに気付いていますか? 'f()'によって返された一時的なものは、新しい(コピーコンストラクタで)割り当てられたメモリにコピーされ、次に破棄されます。そして、それはあなたが見ているデストラクタです。 –

答えて

5

コピーelisionは、C++ 17までのオプションの最適化であり、場合によってはC++ 17でも必須です。私が覚えている限り、(N)RVOのコピーエリートはC++でも必須ではありません - 唯一必須のコピーエリシジョンのケースは一時的な初期化です。

(N)RVOはプログラムの動作を決して変更してはならず、プログラムが正常に機能するためには必要ありません。あなたはそれが(N)RVOにかかわらず、正常に動作するようにあなたのコードを書き、単に速いとき/ IF(N)RVOキックで動作する必要があります。

は、GCC 5.4.0の場合
+0

私はこれを読んで(http://stackoverflow.com/a/12953129/7374642)、elion _can_ alter program behaviourをコピーする:それはas-ifルールコピーコピーエリートを削除する唯一の最適化形式です物体のコピー/移動が副作用を有していても適用することができる。 – fdgsydfgsdfgsdfg

+2

@fdgsydfgsdfgsdfg明確にするために、(N)RVOは、プログラムが一時的および副作用の作成に依存する場合、プログラムの動作を変更する可能性があります。 SergeyAのポイントは、あなたのプログラムがそのような副作用に決して依存してはならないということです。そうでなければ、(N)RVOは動作を変更しません。 – user2079303

+0

はい、コピーelisionに頼るのは悪い考えでした...私はこれを得ました;-) – fdgsydfgsdfgsdfg

2

デストラクタがあります呼ばれる、全くコピーの省略は実行されません。

start 
dtor derived 
dtor base 
done. should have leaked! 

実は、エリジオンを行ったコピー。そうでなければあなたは見たでしょう

start 
dtor derived 
dtor base 
dtor derived 
dtor base 
done. should have leaked! 

ここでは、2つの機会があります。 1つはfのRVO(NRVOではなく、通常の名前のないRVOであることに注意してください)ともう1つは一時的なものから*derivedのコピー構成です。 GCC 5.4.0は、可能なコピーの1つを実行しました。

すべて...エリジオンを実行しても正常にderivedが指すメモリをリークし、正常メモリ

にGCC 5.4.0を漏らします。他のコンパイラは、5.4.0が作成し、その後破棄した一時ファイルを作成しませんでした。

私はinternetz間で異なる場所を読んで、コンパイラは、コピーの省略を行うことが許可されますがを必要とされていません。

正しい。

だから、これはGCC 5.4.0

号にバグで常にコピーの省略を実装していないコンパイラは、標準に準拠しています。あなたの質問から私の前の引用のハイライト部分を見てください。

+0

elisionが実行されました:あなたは正しいです。 gccを '-fno-elide-constructors'と呼ぶと、メッセージの2倍のメッセージが出力されます。 – fdgsydfgsdfgsdfg

関連する問題