2016-06-01 6 views
4

は、次のコードスニペットを考えてみましょう:それはg++clang++と出力と罰金コンパイルmoveコンストラクタを実装することは戻り値の最適化にどのように影響しますか?

#include <iostream> 
#include <string> 

class A { 
public: 
    A() { 
     std::cout << "A::A()\n"; 
    } 

    ~A() { 
     std::cout << "A::~A()\n"; 
    } 

    A(const A&) = delete; 

    A(A&&) { 
     std::cout << "A::A(A&&)\n"; 
    }; 

}; 

A f() { 
    A a; 
    return a; 
} 

int main() { 
    A a = f(); 
    return 0; 
} 

RVOが、その場合にはで蹴るように思え

A::A() 
A::~A() 

です。移動コンストラクタは呼び出されていないことに注意してください。しかしながら

、一方がコード上およびスニペットから未使用の移動コンストラクタは、このになることを削除する場合:

#include <iostream> 
#include <string> 

class A { 
public: 
    A() { 
     std::cout << "A::A()\n"; 
    } 

    ~A() { 
     std::cout << "A::~A()\n"; 
    } 

    A(const A&) = delete; 

}; 

A f() { 
    A a; 
    return a; 
} 

int main() { 
    A a = f(); 
    return 0; 
} 

clang++g++両方が原因クラスAのコピーコンストラクタでこれをコンパイルすることを拒否されます削除済みとマークされているため、RVOが実行されていないようです。

未使用の移動コンストラクタを削除すると、これにつながる可能性がありますか?

+0

私のためにうまくコンパイルします。 'Apple LLVM version 7.3.0(clang-703.0.31)'を使っています。また、http://ideone.com/xTpD56 –

+0

コピーコンストラクタを宣言した場合、移動コンストラクタは暗黙的に宣言されません。 –

答えて

4

copy elisionの最適化では、コピー/移動コンストラクタが存在し、アクセス可能でなければならないことに注意してください。また、それぞれの場合にコピーエリミッションが実行されることは保証されていません。

(強調鉱山)

何の最適化 はすべてで起こっていないかのようにコピーの省略が行われ、著作/移動、コンストラクタが と呼ばれていない、場合でも、それは(存在し、アクセスできる必要があります)、それ以外の場合はプログラムが不正です。あなたのコードの場合

、移動の両方、その後、コピーコンストラクタはdelete編となっている、とあなたは移動コンストラクタの定義を削除すると、そのクラスAは、ユーザー定義のデストラクタを持っているので、それは暗黙的に宣言されることはありません/ copyコンストラクタが存在せず、アクセス可能でないため、コンパイルに失敗しました。

要約すると、ここではコピー/移動構文が必要であり、コンパイラがそれをチェックします。次に、コンパイラはコピーエリシエーションを実行するかどうかを決定します(デバッグモードなど)。

BTW:clangとgccで-fno-elide-constructorsを使用すると、禁止することができます。

+0

私は、rvoを適用する前にコンパイラがどのコンストラクタ(コピーまたは移動)を使用して関数からローカルに戻すかを選択しません。それは定義されていますか? –

+0

@Anton Compilerが最もよくマッチしています。値がrvalueで、move ctorがavailaleの場合、呼び出されます。 rvalueでないか、またはmoveコンストラクタが使用できない場合は、copy ctorが使用されます。その点で、通常の関数のオーバーロード解決とは変わりません。 – SergeyA

+0

@Antonはい、どちらが選択されるかはよく定義されています。あなたのコードでは、 'f()'がrvalue参照にバインドされる可能性があるテンポラリを返すので、move ctorが選択されます。とにかくそれは別の問題であるようです。 – songyuanyao

3

(N)RVOは最適化であることに留意する必要があります。たとえそれが始動したとしても、コードはコピー(または移動)コンストラクタを使用して値が構築されるという標準に準拠している必要があります。コンストラクタが最終的に呼び出されない場合でも、コンストラクタは使用可能でなければなりません。

最適化のために呼び出されないコンストラクタが見つからない場合は、そのコンストラクタが見つからないようにするための提案がありますが、実装されるかどうかは疑問です。

+0

これは、最初のスニペットでは、 'f'のローカル関数' f'がmove-semanticsによって返されていて、オプティマイザがrvoを使用してmove-constructorの呼び出しを外すことを決定するのでしょうか? –

+0

コンパイラでは何が起こるのかは分かりません:)しかし、コードは正しいものでなければならず、最適化されたものでなければなりません。 – SergeyA

+0

言い換えましょう:move ctorが定義されアクセス可能で、 'f'からローカルの' a'を返すことができるので、最初にコードを抜きましたか? –

-3

もしあなたがコピーコンストラクタを持っていれば、正しくリコールすれば移動コンストラクタも必要です。

+0

これはせいぜいコメント(および間違ったもの)です。決して答えはありません。 – SergeyA

関連する問題