移動コンストラクターが呼び出されるタイミングとコピーコンストラクターが呼び出されるタイミングについて混乱しています。私は次の情報源を読みました:
これらのソースはすべて、複雑すぎるか(簡単な例が必要です)、moveコンストラクターの記述方法のみを示しており、呼び出し方法は示していません。より具体的に、簡単な問題を書きました。
const class noConstruct{}NoConstruct;
class a
{
private:
int *Array;
public:
a();
a(noConstruct);
a(const a&);
a& operator=(const a&);
a(a&&);
a& operator=(a&&);
~a();
};
a::a()
{
Array=new int[5]{1,2,3,4,5};
}
a::a(noConstruct Parameter)
{
Array=nullptr;
}
a::a(const a& Old): Array(Old.Array)
{
}
a& a::operator=(const a&Old)
{
delete[] Array;
Array=new int[5];
for (int i=0;i!=5;i++)
{
Array[i]=Old.Array[i];
}
return *this;
}
a::a(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
}
a& a::operator=(a&&Old)
{
Array=Old.Array;
Old.Array=nullptr;
return *this;
}
a::~a()
{
delete[] Array;
}
int main()
{
a A(NoConstruct),B(NoConstruct),C;
A=C;
B=C;
}
現在、A、B、およびCはすべて異なるポインタ値を持っています。 Aに新しいポインターを、BにCの古いポインターを、Cにnullポインターを持たせたいのですが。
ややオフトピックですが、これらの新機能について詳細に学ぶことができるドキュメントを提案できれば、私は感謝し、おそらくこれ以上多くの質問をする必要はないでしょう。
移動コンストラクターは次のように呼び出されます。
std::move(something)
の場合std::forward<T>(something)
であり、T
が左辺値参照型ではない場合(「完全な転送」のためのテンプレートプログラミングで役立ちます)これは完全なリストではありません。パラメータがクラスタイプ(参照ではない)の場合、「オブジェクト初期化子」は関数の引数になる可能性があることに注意してください。
a RetByValue() {
a obj;
return obj; // Might call move ctor, or no ctor.
}
void TakeByValue(a);
int main() {
a a1;
a a2 = a1; // copy ctor
a a3 = std::move(a1); // move ctor
TakeByValue(std::move(a2)); // Might call move ctor, or no ctor.
a a4 = RetByValue(); // Might call move ctor, or no ctor.
a1 = RetByValue(); // Calls move assignment, a::operator=(a&&)
}
まず第一に、あなたのコピーコンストラクタは壊れています。オブジェクトからのコピーとオブジェクトへのコピーの両方が同じArray
を指し、スコープ外になると両方ともdelete[]
を試み、未定義の動作になります。これを修正するには、アレイのコピーを作成します。
a::a(const a& Old): Array(new int[5])
{
for( size_t i = 0; i < 5; ++i ) {
Array[i] = Old.Array[i];
}
}
現在、両方の代入ステートメントが右辺値を使用する代わりに左辺値から割り当てているため、ムーブ代入は期待どおりに実行されていません。移動を実行するには、右辺値から移動するか、左辺値を右辺値と見なすことができるコンテキスト(関数のreturnステートメントなど)である必要があります。
目的の効果を得るには、 std::move
を使用して右辺値参照を作成します。
A=C; // A will now contain a copy of C
B=std::move(C); // Calls the move assignment operator
コピーの省略が発生する可能性があることに注意してください。 -fno-elide-constructors
フラグをコンパイラーに渡して無効にすると、コンストラクターが実行される可能性があります。
あなたはここでそれについて読むことができます: https://www.geeksforgeeks.org/copy-elision-in-c/