R-value reference のつづき。
先だってのエントリ、正確さに欠ける言い回しがあったかな。
R-value reference / move semantics は、右辺値からそのナカミをmoveする機能じゃありません。
右辺値であればそれは一時オブジェクトであり、いずれ捨てられる運命。
↓
ならば右辺値からナカミをひっぺがして使える。
↓
そのためには、もらった引数が右辺値であることが識別できるからくりが言語レベルで必要。
↓
右辺値を T&& にmatchさせて関数を呼び分けてあげよう。
ってゆースンポーです。実際にナカミをひっぺがすのはプログラマのお仕事。言語サイドではナカミをひっぺがす、つまり移動(move)可能ってゆー意味(semantics)を伴って呼び出されたことをプログラマに教えてあげるカラクリを用意してくれた。ってーのが右辺値参照の意味となりますか。
んでもって右辺値参照のサンプル、ショボい文字列 shobostr をこしらえてみんとす。
#include <iostream> // cout,err
#include <utility> // move
#include <cstring> // strほげほげ()
using namespace std;
// ショボい文字列
class shobostr {
private:
char* body;
public:
// デフォルト コンストラクタ
shobostr() : body(nullptr) { cerr << "ctor()\n"; }
// C文字列を食うコンストラクタ
shobostr(const char* cstr) {
cerr << "ctor(const char*)\n";
body = new char[strlen(cstr)+1];
strcpy(body,cstr);
}
// コピー コンストラクタ
shobostr(const shobostr& ss) {
cerr << "ctor(const shobostr&)\n";
body = new char[strlen(ss.body)+1];
strcpy(body,ss.body);
}
#ifdef RVR
// 右辺値参照 コンストラクタ
shobostr(shobostr&& rvr) {
cerr << "ctor(shobostr&&)\n";
body = rvr.body; // 引数から引き剥がすよ
rvr.body = nullptr;
}
#endif
// デストラクタ
~shobostr() {
cerr << "dtor() for " << (body ? body : "(null)") << '\n';
delete[] body;
}
// C文字列を代入
shobostr& operator=(const char* cstr) {
cerr << "operator=(const char*)\n";
delete[] body;
body = new char[strlen(cstr)+1];
strcpy(body,cstr);
return *this;
}
// コピー
shobostr& operator=(const shobostr& ss) {
cerr << "operator=(const shobostr&)\n";
if ( &ss != this ) {
delete[] body;
body = new char[strlen(ss.body)+1];
strcpy(body,ss.body);
}
return *this;
}
#ifdef RVR
// 右辺値参照 コピー
shobostr& operator=(shobostr&& rvr) {
cerr << "operator=(const shobostr&)\n";
if ( &rvr != this ) {
delete[] body;
body = rvr.body; // 右辺から引き剥がすよ
rvr.body = nullptr;
}
return *this;
}
#endif
// 連結
friend shobostr operator+(const shobostr& lhs, const shobostr& rhs) {
cerr << "operator+(const shobostr&,const shobostr&)\n";
shobostr result;
result.body = new char[strlen(lhs.body)+strlen(rhs.body)+1];
strcpy(result.body, lhs.body);
strcat(result.body, rhs.body);
return result;
}
};
// こっからおためし
int main() {
shobostr s0("Hello,");
shobostr s1("world");
shobostr s2(s0+s1);
}
実行結果:
--- RVR disabled ---
ctor(const char*)
ctor(const char*)
operator+(const shobostr&,const shobostr&)
ctor()
ctor(const shobostr&) ← s2:コピーコンストラクタ
dtor() for Hello,world ← +の結果を捨ててるMOTTAINAIトコ
dtor() for Hello,world
dtor() for world
dtor() for Hello,
--- RVR enabled ---
ctor(const char*)
ctor(const char*)
operator+(const shobostr&,const shobostr&)
ctor()
ctor(shobostr&&) ← s2: 右辺値参照版 コピーコンストラクタ
dtor() for (null) ← operator+の戻り値からbodyが移動してゆー
dtor() for Hello,world
dtor() for world
dtor() for Hello,