1
#include <string> 
#include <iostream>

struct A 
{
   A (){}

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

    A& operator =(A)
    {
        return *this;
    }
}; 

int main()
{ 
    A  a;
    A a2;

    a=std::move(a2);

    std::cin.ignore();

    return 1;
}

コピー省略のルールは、引数が xvalue ではなく prvalue でなければならないということですが、なぜですか?

4

1 に答える 1

7

コピー省略のルールは、引数が xvalue ではなく prvalue でなければならないということですが、なぜですか?

プログラムには、コピー/移動省略を実行できる状況が含まれていません。C++11 標準では、パラグラフ 12.8/31 でこれらの状況を正確に指定しています。

特定の基準が満たされると、コピー/移動操作用に選択されたコンストラクターおよび/またはオブジェクトのデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。[...] コピー省略と呼ばれるこのコピー/移動操作の省略は、次の状況で許可されます(複数のコピーを排除するために組み合わせることができます)。

— クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cv-unqualified 型を持つ不揮発性自動オブジェクト (関数または catch-clause パラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます

これはあなたの状況ではありません。あなたreturnによって編集された式operator =is*thisであり、これは自動保存期間を持つオブジェクトの名前ではないからです。さらに、とにかくの結果を保存していませoperator =ん。

— throw 式で、オペランドが非 volatile 自動オブジェクト (関数または catch 句パラメーター以外) の名前であり、そのスコープが最も内側の try ブロックの末尾を超えて拡張されていない場合 (存在する場合) 1 つ)、オペランドから例外オブジェクト (15.1) へのコピー/移動操作は、自動オブジェクトを例外オブジェクトに直接構築することによって省略できます。

式がないため、これは当てはまりませんthrow

—参照 (12.2) にバインドされていない一時クラス オブジェクトが同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合、一時オブジェクトを省略したコピー/移動の対象

一時値がないため、これも当てはまりません ( xvalueは一時値ではありません)。

— 例外ハンドラーの例外宣言 (条項 15) が、例外オブジェクト (15.1) と同じ型 (cv 修飾を除く) のオブジェクトを宣言する場合、コピー/移動操作は、例外宣言を処理することによって省略できます。 exception-declaration によって宣言されたオブジェクトのコンストラクタとデストラクタの実行を除いて、プログラムの意味が変更されない場合は、例外オブジェクトのエイリアスとして。

コードには例外ハンドラがないため、この状況も当てはまりません。


あなたの意図した質問が「なぜ物事はそのようになっているのか?」である場合、私が提供できる客観的で網羅的な答えはありません (他の人はそうかもしれませんが)。しかし、私はいくつかのもっともらしい議論をしようとします。

上記の標準の段落で指定されているように、returnステートメントの場合のコピー省略は、割り当てられたオブジェクトに直接返されるオブジェクトを関数が構築できることを意味します。

具体的には、これはおそらくコンパイラが、自動ストレージを持つローカル オブジェクトではなく、戻り値が割り当てられるオブジェクトで直接動作し、呼び出された関数のスタック フレームの外側に存在するその関数のコードを生成することを意味します。関数のスタック フレームに割り当てられた期間。これは、割り当てられたオブジェクトのエイリアスとしてローカル オブジェクトを表示できることを意味します。

ただし、ここでは2 つの非常に異なるオブジェクトがあり、どちらも物質的に構築されており、どちらもメモリを必要とし、2 つの異なるアドレスに存在します。前に概説したものと同様のトリックを適用する方法はありません。そのようなエイリアシングでは、プログラムの実行中にオブジェクトのアドレスを変更する必要があり、それは違法です。

于 2013-04-07T16:32:23.873 に答える