2016-08-24 8 views
4

C++で文字列クラスをコーディングしているとします(ライブラリを使用できることがわかります)。ストリングの長さは可変であり、ストレージスペースはコンストラクターで動的に割り当てられ、デストラクタで解放されます。 main関数(a,b,cが文字列である)c=a+bを呼び出すときに、operator+メンバ関数は、連結された文字列a+bを格納する一時的なオブジェクトを作成main機能に戻し、その後operator=メンバ関数は元々cに格納された文字列を解放するために呼び出されますテンポラリ文字列a+bからcにデータをコピーし、最後にテンポラリa+bを破棄します。これを実現するための方法があるかどう値で返されるのではなく、C++でスワップを返すことは可能ですか?

私は思ったんだけど:代わりにca+bからoperator=コピーデータを有するので、私は、それがa+bcのデータポインタを交換したいようa+bが破壊されたときに、それをc(元のデータ)に元のデータが破棄されますが、cは今度はa+bの結果をコピーする必要はありません。

2パラメータのメンバ関数setToStrcatをコーディングし、c.setToStrcat(a,b)を呼び出すことができます。たとえば、関数を符号化することができる。

void String::setToStrcat(const String& a,const String& b){ 
     String tmp(a.len+b.len); int i,j; 
     for(i=0;i<a.len;i++) tmp[i]=a[i]; 
     for(j=0;j<b.len;i++,j++) tmp[i]=b[j]; 
     tmp[i]='\0'; this->swap(tmp); 
    } 

    void String::swap(String& a){ 
     int n=len; len=a.len; a.len=n; 
     char *s=str; str=a.str; a.str=s; 
    } 

は私のコンストラクタの定義を省略(i番目の文字の参照を返す)とoperator[]len+1 char型のスペースを割り当てています)。 tmpがスワップ後破壊されたとき、それが実際に破壊されている元々*thismain関数でString c)に格納されたデータとなるようswap関数は、*thistmp間のデータポインタと長さ変数をスワップ。 *thisは現在(c.str)の連結文字列a+bです。

c=a+bのパフォーマンスを同じレベルに最適化する方法があるかどうかを知りたいと思います。私はc.swap(a+b)を試して、a+bの戻り値の型をString&に変更しましたが、警告(ローカル変数への参照)が表示され、GDBはスワップが発生する前に一時的に破壊されたことを示します。

私の質問は一般的だと思います。 C++プログラミングでは、関数の結果を格納するために一時オブジェクトが必要なことがよくありますが、main関数の別のオブジェクトに割り当てると、データをコピーすることはできませんが、代わりに(もっと速く)ポインタのスワップを使用できますか?これを実現させるためのきちんとした方法は何ですか?

+4

移動のセマンティクスを検索します。具体的には、コンストラクタを移動して代入演算子を移動します。 – Rakete1111

+2

まだ移動のセマンティクスについて聞いたことがありませんか? [お読みください。](https://www.google.com/search?q = c%2B%2B + move + semantics) – user2357112

+2

あなたは[copy elision]のように見えます(http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value最適化)。 C++では、C++以降に保証されます。 – Sergey

答えて

1

C++ 11では、ムーブコンストラクタを記述することでこれを行うことができます。この正確な問題を解決するために、Rvalue参照が言語に追加されました。

class String { 
    ... 
    String(String&& s) : str(nullptr) { 
    this->swap(s); 
    } 
    String& operator=(String&& s) { 
    this->swap(s); 
    } 
    ... 
    String operator+(String const& other) { 
    // (your implementation of concatenation here) 
    } 
    ... 
} 

次に、このようなコードは、余分なコピーコンストラクタやメモリ割り当てをトリガーしません、それは単に新しいオブジェクトcに(オペレータ+から返されたもの)の一時から割り当てられたメモリを移動します。

String c = a + b; 
+0

'String c = a + b;'とにかくコピーエリジョンを実行する可能性があります。 –

+0

参照してください。一時的な文字列「a + b」はrvalueである。それを参照するために、私はrvalue参照を使用する必要があります。 'String'クラスの' operator = 'は、2倍のオーバーロード、1つは左辺値の参照と深いコピー、もう1つは右辺値の参照とポインタのスワップを行うことができます。コンパイラがどちらを呼び出すかを決めることができないときは、明示的にrvaluesに変換するために 'std :: move'セマンティクスを使用します。もう1つ質問があります: 'a + b'は' c = a + b'の後でもまだ破壊されていますか? –

+0

はい、破壊されましたが、 'nullptr'を含んでいますので、何も割り当てを解除しません。 –

関連する問題