ゆとりーなの日記

日記的な事を書いて行くと思はれる

moveが定期的にわからなくなる

 moveとconstに絡むことがまだよく消化しきれていないところが自分の中にあるのですね。

class A {
  A() {}
  A(const A&) = default;
  A(A &&) = default;
};

int main() {
  const A x;
  A y(std::move(x));
}

に於いてはコピーコンストラクが呼ばれるってことには大分慣れてきたのですが、今日あれって思ったのが、

class A {
  A() {}
  A(const A&) = default;
  A(A &&) = default;
};

class B {
  B() : a() {}
  B(const B&) = default;
  B(B &&) = default;

  const A a;
};

int main() {
  B x;
  B y(std::move(x));
}

の時にBはムーブコンスタクタが呼ばれ、Aに関してはコピーコンストラクタが呼ばれるってのに一瞬びっくりしてしまいました。なんというか、Bでムーブコンストラクタに突入できたので、「しめしめ、Aもムーブされるあるで!」とかいうよく分からない幻想に取り付かれてしまったようです。よく考えたらムーブコンストラクタの初期化子内で、最初の例のようなことが起こるだけなので、ちょっと考えればムーブされないだろうことは容易に想像できるはずなのに、ちょっとこれではいけませんね。
 おまけとして今日分かったかもなことに、constが付いた物に関してだけムーブされない原則なるものがあるのではないかということがあります。FDISに当たってないので見当違いかもしれませんが、一つ前の例でいえば、xにはconstが付いていないので、ムーブコンストラクタが呼ばれるが、中のaはconstなのでムーブではなくコピーになる、一方で、最初の例のxはxにconstが付いているのでコピーコンストラクタが呼ばれるって具合になっています。
 詰まり、一旦コピーの段階に突入してしまえば以下中の子も全てコピーになってしまうのですが、ムーブに突入しても、ムーブ出来ないものがあれば、勝手にコピーに置き換わるってことです。逆に云えば、中の子でムーブ出来ないものがあるから全部コピーにしなければ、とはならないってことです。
 これを使えば、組み込み型や組み込み型のみで構成されているクラス等のメンバはconstにして、std::string等、コピーは重くてムーブが軽い子達だけ非constにするということが成立してくるのではないかと思えます。基本的に再代入はロクなことがないのでconstを付けて封じるにこしたことはないので、積極的に付けていきたいところなのですが、ムーブのことを考えると迂闊に付けられない時代になってきたのかと思っていました(まぁNRVOとかが効くことも多いんでそんなに気にしなくてもいいのかなとも思っていましたが)。
 唯、共にconstにしたいところなのに、組み込み型的サムシングにはconst付き、std::stringのようなものはconstなしという宣言のクラスがあると、見た目違和感があるのかなぁという気がしないこともないです。そう考えると全部非constの方が見栄えがいいのかなと思わないこともないです。まぁこれは関数宣言の引数constがなくて実装ではあるのが気持ち悪いか否かとかの気分の問題のような気もするので、好みの問題なのかもしれません。