短い答え
コピー可能だからです。
長い答え
まず、「移動」が実際に何を意味するのかを明確にする必要があります。Von Newmanマシンはデータを移動しません:あなたはただ「コピー」します。データはメモリロケーションから別のロケーションにコピーされます。「動かされた」ことはありません。
しかし、より高い抽象化レベルでは、データは他のデータへの単なるポインターになる可能性があります。コピーされたポインターを無効にするポインターをコピーすると、参照されたデータは、ある「所有者」から別の「所有者」に「移動」されたと言われます。
より一般的には、値をコピーし(ポインタに含まれるアドレスをレイクする)、元の値を破棄して認識可能な「無効」に設定する操作は、「移動」と呼ばれます。
C ++に関しては、wheはさまざまなタイプのオブジェクトを区別できます。
- 単純な値だけを含むもの。
- それらが参照するものを「所有する」単純なポインタまたは参照のみを含むもの
- 単純なポインタまたは参照だけを含み、それらが参照するものを「負わない」もの
- 巨大な値を含むもの。
- 物理エンティティまたはオペレーティングシステム(より一般的な「ホスティングプラットフォーム」)エンティティを表すもの。
このタイプのすべてについて、「コピー」と「移動」の概念は異なる意味を持っている可能性があり、その場合の一部の操作または他の操作はまったく意味を持たない可能性があります。
次に、タイプ1オブジェクトについて考えます。
int a=5; c=0;
c = a;
c = std::move(a);
a
引っ越し後の価値は何だと思いますか?どうc = a+b
ですか?aとbを「移動」する必要がありoperator+
ますか?
ここで、タイプ2のオブジェクトについて考えてみます。
std::unique_ptr<int> pa(new int(5)), pb;
pb = std::move(pa);
ここには、2つのスマートポインター(両方ともスコープの終了時に破棄されます)と1つの整数のみがあります。1回だけ実行できる操作(delete
この場合は、)があるため、整数の「所有権」を保持する必要があるポインターは1つだけです。これは、「コピー」が無意味であり、移動が唯一のサポートされている操作である場合です。
次に、タイプ3のオブジェクトについて考えます。
std::list<int> lst = { 1,2,3,4 };
auto i = lst.begin();
auto j = i;
*j = *i+5;
++i;
*i = *j;
これは完全に理にかなっています。リストを。にするだけ{ 6,6,3,4 }
です。イテレータは、参照するものを所有していません。すべて同じ値を参照しているイテレータが多数存在する可能性があります。コピーは理にかなっていますが、移動は意味がありません。(コピーの代わりに)移動i
すると、*iと++iは使用できなくなります。j
次に、タイプ4のオブジェクトについて考えます。
class A
{
int m[15000000]; //15 million integers
public:
int& operator[](unsigned x) { return m[x]; }
const int& operator[](unsigned x) const { return m[x]; }
};
このような巨大な獣は、ほとんどのシステムのスタックに割り当てるのに問題があります。ほとんどの場合、ヒープに残り、(スマート)ポインターによって所有/参照されます。そのアドレスはポインタ間で移動されますが、オブジェクト自体は移動できません。それでもコピー可能である可能性があります。
別の微妙なケースがあります:A自体が動的に割り当てられた巨大な配列へのポインタである場合:これはstd :: vectorと同じです:動的に割り当てられたデータを所有するのはそれ自体が「スマートポインタ」であるため移動可能ですが、所有するデータの新しい別のコピーが必要になる場合があるため、コピー可能にすることもできます。
タイプ5を検討します。
class window
{
private:
HWND handle;
public:
window() :handle(CreateWindow(....))
{ .... }
~window() { DestroyWindow(handle); }
};
ここで、のインスタンスは画面上に存在するウィンドウwindow
を表します。「コピー」または「移動」とはどういう意味ですか?
これは、コピーと移動の両方が無効になっている、などmutex
の場合に最もよく発生します。condition_variable