2

私は、右辺値参照がクラスの設計にどのように影響するかを評価しようとしていました。以下に示すように、既存のクラスがあるとします。

class X
{
   string internal;

public:
   void set_data(const char* s)
   {
      internal = s;
   }
..
..
..
//other stuff

};

このクラスは、次のような別のモジュールによって使用されます。

//another module
{

    string configvalue;
    X x;

    //read configvalue from a file and call set 

    ...
    x.set_data(configvalue.c_str());

    //use x to do some magic
    ..
    ...


}

右辺値参照が適切に配置されている場合は、そのような別のメンバー関数を提供する方がよいでしょう。

class X
{
...
...
....
 void set_data(string s)
 {
     internal = std::move(s);
 }
};

これにより、このクラスのクライアントは移動セマンティクスを使用できるようになり、使用ごとに1セットの割り当て/コピー操作を防ぐことができます。これは高度に作成された例ですが、「最小限のインターフェイス」パラダイムを破ることなく、すべてのクラス設計に同じ原則が適用されます。

この問題に関する洞察は大歓迎です。

4

2 に答える 2

4

はい、stringあなたが提案するようにオーバーロードを追加することは良い考えです。右辺値参照がなくても、このようなオーバーロードは良い考えです。それ以外の場合、 が与えられた場合、それstd::string sを使用するには次のことを行う必要があります。

x.set_data(s.c_str());

一方

x.set_data(s);

のクライアントにとって、はるかに直感的です (さらにはわずかに効率的です) X

別のオプションとして、次の 2 つのオーバーロードを追加できます。

void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}

これは、あなたが正しく提案した単一のオーバーロードとほぼ同じです。2 つのオーバーロード ソリューションには、パフォーマンス上のわずかな利点があります。string渡された引数が xvalue (でキャストされた左辺値) である場合、単一のオーバーロード ソリューションでは、追加のmove 構築が必要になりますstd::move。しかし、 の移動コンストラクターはstd::string非常に高速である必要があるため、これは大したことではありません。私はそれを完全な開示の精神でのみ言及します.

複数のパラメーターがある場合set_data、「値による」アプローチはより魅力的になります。たとえば、2 つの s を渡す必要がある場合を考えてみましょうstring。選択肢は次のとおりです。

解決策 1

void set_data(string s1, string s2);

解決策 2

void set_data(const string&  s1, const string&  s2);
void set_data(      string&& s1, const string&  s2);
void set_data(const string&  s1,       string&& s2);
void set_data(      string&& s1,       string&& s2);

すぐにわかるように、ソリューション 2 はパラメーターの数に応じてうまくスケーリングしません。

最後に、決して両方のソリューションを同じタイプに適用しようとしないでください。

これをしないでください!

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}

このオーバーロードのセットはあいまいです。C++03 と同様に、次の 2 つのオーバーロードがあいまいです。

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}

左辺値参照でも右辺値参照でも、値による参照をオーバーロードしないでください。

于 2012-11-16T22:41:17.143 に答える
-1

インターフェイスの一部として と の両方void set_data(const char* s)を使用する理由がわかりません。void set_data(string s)これにより、あいまいさが生じ、副作用が発生しやすくなります。さらに、 への呼び出しで引数を値で渡しますset_data(string s)。代わりに、次の 2 つの関数を定義することをお勧めします。

void set_data(const string &s);
void set_data(string &&s);

このようにして、2 つの実装を持つことができます。1 つ目は文字列をディープ コピーし、2 つ目は文字列であるため、文字列の内部を盗むことができますrvalue(デストラクタが問題なく破棄できるように、定義された状態のままにしておく必要があります。詳細はhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semanticsを参照してください)。

rvalue string2 番目のバージョンは、引数で、または引数が によって強制された場合に自動的に呼び出されrvalueますstd::move

値によるオプションも必要な場合はrvalue、この API のバージョンを文字列コピー コンストラクターと組み合わせて使用​​できますset_data(string(str))

于 2012-11-16T09:30:41.400 に答える