3

私は、知識を学び、固めるためだけに、独自の文字列クラスを作成しています。std::string で移動セマンティクスを使用するコンストラクターが必要な場合を除いて、すべてが機能しています。

コンストラクター内で std::string データ ポインターなどをコピーして null にする必要があります。文字列が指すデータを削除せずに、空ではあるが有効な状態のままにしておく必要があります。

これまでのところ、私はこれを持っています

class String
{
private:
char* mpData;
unsigned int mLength;
public:
String( std::string&& str)
    :mpData(nullptr), mLength(0)
    {
    // need to copy the memory pointer from std::string to this->mpData

    // need to null out the std::string memory pointer
    //str.clear();  // can't use clear because it deletes the memory
    }
~String()
{
delete[] mpData;
mLength = 0;
}
4

3 に答える 3

7

これを行う方法はありません。の実装std::stringは実装定義です。すべての実装は異なります。

さらに、文字列が動的に割り当てられた配列に含まれるという保証はありません。一部のstd::string実装では、小さな文字列の最適化を実行します。この場合、小さな文字列はstd::stringオブジェクト自体の内部に格納されます。

于 2012-07-28T04:19:30.220 に答える
1

以下の実装は要求されたものを達成しますが、多少のリスクがあります。

このアプローチに関する注意事項:

  • std::string を使用して、割り当てられたメモリを管理します。私の見解では、このように割り当てを階層化することは、単一のクラスが達成しようとすることの数を減らすため、良い考えです (ただし、ポインターを使用するため、このクラスには、コンパイラーによって生成されたコピーに関連する潜在的なバグがまだあります)オペレーション)。

  • オブジェクトdeleteによって自動的に実行されるようになったため、この操作を廃止しました。allocation

  • を使用して基になるデータを変更すると、いわゆる未定義の動作が発生します。ここmpDataに示されているように、未定義です。これは、標準が未定義であると述べているためです。とはいえ、動作が異なる実際の実装が存在するかどうかは疑問に思います-- そのような変更が完全に合法である場合。を介した変更が への後続のアクセスに反映されない可能性はありますが、この質問の議論に基づくと、オブジェクトを介してそれ以上変更が行われないと仮定すると、そのような変更が予期しない動作をもたらす可能性は非常に低いようです。const char * std::string::data()T * std::vector::data()data()allocationallocation

  • 移動セマンティクスに対して本当に最適化されていますか? それは実装定義かもしれません。また、受信文字列の実際の値に依存する場合もあります。他の回答で述べたように、移動コンストラクターは最適化のメカニズムを提供しますが、最適化が行われることを保証するものではありません。


class String
{
private:
char* mpData;
unsigned int mLength;
std::string allocation;
public:
String( std::string&& str)
    : mpData(const_cast<char*>(str.data())) // cast used to invoke UB
    , mLength(str.length())
    , allocation(std::move(str)) // this is where the magic happens
    {}
};
于 2012-09-23T00:39:36.827 に答える
-1

私はこの質問を、「ムーブ コンストラクターの結果を正しい動作にすることができますか」解釈しています。

質問が厳密に「std::string から内部メモリを盗むポータブルな方法はありますか」である場合、答えは「いいえ、パブリック API で提供される「メモリ所有権の転送」操作がないため」です。


この移動セマンティクスの説明からの次の引用は、「移動コンストラクター」の優れた要約を提供します...

C++0x では、「右辺値参照」と呼ばれる新しいメカニズムが導入されています。これにより、関数のオーバーロードによって右辺値引数を検出できるようになります。右辺値参照パラメーターを使用してコンストラクターを作成するだけです。そのコンストラクター内では、ソースを何らかの有効な状態にしておく限り、ソースに対して必要なことを何でも行うことができます。

この説明に基づいて、実際に内部データ バッファーを盗む義務を負うことなく、「ムーブ セマンティクス」コンストラクター (または「ムーブ コンストラクター」) を実装できるように思えます。実装例:

String( std::string&& str)
    :mpData(new char[str.length()]), mLength(str.length())
    {
    for ( int i=0; i<mLength; i++ ) mpData[i] = str[i];
    }

私が理解しているように、移動セマンティクスのポイントは、必要に応じてより効率的にできるということです。着信オブジェクトは一時的なものであるため、その内容を保存する必要はありません。したがって、それらを盗むことは合法ですが、必須ではありません。おそらく、ヒープベースのオブジェクトの所有権を譲渡しない場合、これを実装する意味はありませんが、合法であるように思われます。おそらくそれは足がかりとして役立つでしょう - たとえそれがすべての内容でなくても、役に立つだけ盗むことができます.

ところで、密接に関連した質問がここにあります。この質問では、同じ種類の非標準文字列が構築されており、std::string の移動コンストラクターが含まれています。ただし、クラスの内部構造は異なります。 std::string には、内部で移動セマンティクスのサポートが組み込まれている可能性があることが示唆されています (std::string -> std::string)。

于 2012-07-28T05:15:07.583 に答える