C++11のgetter/setterについて


そもそもgetter/setterめんどいだけじゃねとか設計的にいらなくね、とかはなしで。

## Move Semanticsの恩恵に与ることができるsetter

すでに知られていることだが、setterと言うのはmoveとcopy両方を集約して書いても構わない(事が多い)。

```setter.cpp
class Foo {
	std::string value;
public:
	Foo() = default;
	~Foo() = default;
	void setValue(std::string value_) {
		value = std::move(value_); // value_は自明にmoveしていい
	}
};

int main(){
	Foo f;
	std::string x = "test1";
	f.setValue(x); // 引数にcopyされて渡る.
	x = "test2";
	f.setValue(std::move(x)); // 引数にmoveされて渡る.
	return 0;
}
```

この場合`sizeof(std::string)`が大きい時にはこの手を使うのは悪手ってことになるけど、だいたいポインタ2つくらいしか使ってないだろうから大したことない。

## rvalue reference for *thisを使わないといけないgetter

一方getterはそう簡単には行かない。以下のコードを見てほしい。

```getter.cpp
#include <cassert>
#include <iostream>
#include <string>

enum class GetterMode {
    LVALUE,
    RVALUE,
    CONST_LVALUE,
};

GetterMode mode;

class Foo {
    std::string value;
public:
    Foo(std::string value): value(value) {}
    ~Foo() = default;
    std::string& getValue() { mode = GetterMode::LVALUE; return value; }
    const std::string& getValue() const { mode = GetterMode::CONST_LVALUE; return value; }
};

int main() {
    Foo x("xxx");
    const Foo y("yyy");
    x.getValue(); // 通常のgetValueが呼ばれる
    assert(mode == GetterMode::LVALUE);
    y.getValue(); // const lvalue版が呼ばれる
    assert(mode == GetterMode::CONST_LVALUE);
    Foo("zzz").getValue(); // lvaue版が呼ばれる
    assert(mode == GetterMode::LVALUE);
    std::string p = Foo("zzz").getValue(); // lvalue版が呼ばれる
    assert(mode == GetterMode::LVALUE);
    std::string r = std::move(Foo("zzz").getValue()); // lvalue版が呼ばれる
    assert(mode == GetterMode::LVALUE);
    x.getValue() = "aaa"; // getterなのに代入できちゃう
}
```

見ての通り多くの問題点がある。

* lvalueの参照を返すgetterと言うのはその参照を使って誰かに値を書き換えられる。つまり実のところgetterを作ったつもりがsetterを作ってしまう。`operator*()`とかはそれでいいんだけどgetterとしてはだめ。
* `Foo("zoo").getValue()`のようなrvalueに対してgetterを読んだ場合も出てくるものが`std::string&`なので、そのまま代入するとコピーコンストラクタが呼ばれてしまう。それを避けるために全体をmoveして`std::move(Foo("zoo").getValue())`のようにしてやらないとだめで直観的でない

こういう時は次のように*thisに対するオーバーロードを利用する。

```getter2.cpp
#include <cassert>
#include <iostream>
#include <string>

enum class GetterMode {
    LVALUE,
    RVALUE,
    CONST_LVALUE,
};

GetterMode mode;

class Foo {
    std::string value;
public:
    explicit Foo(std::string value): value(value) {}

    std::string&& getValue() && { mode = GetterMode::RVALUE; return std::move(value); }
    const std::string& getValue() const& { mode = GetterMode::CONST_LVALUE; return value; }
    // volatile修飾は省略
};

int main() {
    Foo x("xxx");
    const Foo y("yyy");
    x.getValue(); // const lvalue版呼ばれる
    assert(mode == GetterMode::CONST_LVALUE);
    y.getValue(); // const lvalue版が呼ばれる
    assert(mode == GetterMode::CONST_LVALUE);
    Foo("zzz").getValue(); // rvalue版が呼ばれる
    assert(mode == GetterMode::RVALUE);
    std::string p = Foo("zzz").getValue(); // rvalue版が呼ばれる
    assert(mode == GetterMode::RVALUE);
    std::string q = std::move(x).getValue(); // rvalue版が呼ばれる
    assert(mode == GetterMode::RVALUE);
    // x.getValue() = "aaa"; // エラー！
    static_assert(std::is_same<decltype(x.getValue()), const std::string&>::value, "x.getValue() should return const lvalue reference");
    static_assert(std::is_same<decltype(std::move(x).getValue()), std::string&&>::value, "std::move(x).getValue() should return rvalue reference");
    static_assert(std::is_same<decltype(Foo("zoo").getValue()), std::string&&>::value, "Foo(\"zoo\").getValue() should return rvalue reference");
    return 0;
}
```

これで無事にlvalueのgetterはconst lvalue referenceに、rvalueのgetterはrvalue referenceになった。ここまでするの面倒なんでメンバアクセス`foo.value`で済むなら済ませたほうがいい気がします。

### 注意点

まずひとつ、普通のconstメソッドのgetValueの方にも`const&`と書いて **このメソッドは`lvalue this`専用です** ということを明示しないといけない。

あと、rvalue reference to *thisと言うのはgccではすごく最近実装された機能です。

> http://gcc.gnu.org/projects/cxx0x.html
>
> | Language Feature | C++11 Proposal | Available in GCC? |
> |-----|------|-----|
> | Rvalue references for *this | N2439 | GCC 4.8.1 |

clangは早かったみたいですが。

> http://clang.llvm.org/cxx_status.html
>
> | Language Feature | C++11 Proposal | Available in Clang? |
> |-----|------|-----|
> | Rvalue references for *this | N2439 | Clang 2.9 |

なので、gcc使ってるとまだまだ使えない事が多いと思うので注意してください。

### 追記 (2014-06-10)
添付のソースが嘘ソースだったので修正