basic_string
C ++ 11以降ではCOWは禁止されていますか?
について
」アム私はC ++ 11がのCOWベースの実装を認めていないことを修正しますかstd::string
?
はい。
について
」もしそうなら、この制限は、明示的に(どこ)新規格のどこかに記載されていますか?
ほとんど直接的に、COW実装で文字列データのO( n)物理コピーを必要とする多くの操作の一定の複雑さの要件による。
たとえば、メンバー関数の場合
auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;
…COW実装では、どちらも文字列データのコピーをトリガーして文字列値の共有を解除しますが、C ++ 11標準では
C ++ 11§21.4.5/ 4:
” 複雑さ:一定の時間。
…このようなデータのコピー、つまりCOWを除外します。
C ++ 03によるCOW実装をサポートしていないの呼び出しできるように、これらの一定の複雑さの要件を有し、一定の制約条件の下で、でoperator[]()
、at()
、begin()
、rbegin()
、end()
、またはrend()
文字列の項目を参照無効の参照、ポインタとイテレータに、つまりはおそらく被るAにCOWデータのコピー。このサポートはC ++ 11で削除されました。
COWもC ++ 11無効化ルールによって禁止されていますか?
執筆時にソリューションとして選択された別の回答では、非常に賛成されているため、明らかに信じられており、
」 COW列について、呼び出し非はconst
operator[]
[C ++ 11§21.4.1/ 6]上記[引用]段落によって禁止され、コピーを作成(及び参照を無効化)が必要となります。したがって、C ++ 11でCOW文字列を使用することはもはや合法ではありません。
その主張は不正確であり、主に2つの点で誤解を招きます。
- これは、非
const
アイテムアクセサーのみがCOWデータのコピーをトリガーする必要があることを誤って示しています。
ただし、const
アイテムアクセサーはデータコピーをトリガーする必要があります。これにより、クライアントコードが参照またはポインターを形成できるようになるため(C ++ 11では)、COWデータコピーをトリガーできる操作を介して後で無効にすることはできません。
- COWデータのコピーによって参照が無効になる可能性があると誤って想定しています。
ただし、正しい実装では、COWデータのコピー、文字列値の共有解除は、無効化できる参照がある前の時点で行われます。
の正しいC ++ 11 COW実装がどのように機能するかを確認するbasic_string
ために、これを無効にするO(1)要件が無視される場合、文字列が所有権ポリシーを切り替えることができる実装を考えてください。文字列インスタンスは、ポリシーSharableで始まります。このポリシーがアクティブな場合、外部アイテム参照はありません。インスタンスは一意のポリシーに移行でき、.c_str()
(少なくとも内部バッファーへのポインターを生成する場合)への呼び出しなどでアイテム参照が作成される可能性がある場合は、移行する必要があります。値の所有権を共有する複数のインスタンスの一般的なケースでは、これは文字列データのコピーを伴います。一意のポリシーへの移行後、インスタンスは、割り当てなどのすべての参照を無効にする操作によってのみ、共有可能に戻ることができます。
したがって、COW文字列が除外されているという回答の結論は正しいものの、提示された推論は正しくなく、誤解を招く可能性があります。
この誤解の原因は、C ++ 11の附属書Cの非規範的な注記であると思います。
C ++ 11§C.2.11[diff.cpp03.strings]、§21.3について:
変更:basic_string
要件は参照カウント文字列を許可しなくなりました
根拠:参照カウント文字列との無効化は微妙に異なります。この変更により、この国際規格の動作(sic)が正規化されます。
元の機能への影響:この国際標準では、有効なC ++ 2003コードの実行が異なる場合があります
ここで、理論的根拠は、C ++ 03の特別なCOWサポートを削除することにした主な理由を説明しています。この理由、その理由は、標準がCOWの実装を効果的に禁止する方法ではありません。標準では、O(1)要件によるCOWは許可されていません。
要するに、C ++ 11無効化ルールはのCOW実装を除外しませんstd::basic_string
。しかし、それらは、g ++の標準ライブラリ実装の少なくとも1つにあるような、合理的に効率的な無制限のC ++ 03スタイルのCOW実装を除外します。特別なC ++ 03 COWサポートによりconst
、無効化のための微妙で複雑なルールを犠牲にして、特にアイテムアクセサーを使用して実用的な効率を実現しました。
C ++ 03§21.3/ 5には「ファーストコール」COWサポートが含まれています。
」参照、ポインタ、の要素を参照する反復子basic_string
配列は、以下の使用によって無効にすることができるbasic_string
オブジェクト:
-非メンバ関数への引数としてswap()
(21.3.7.8)、operator>>()
(21.3.7.9)、及びgetline()
(21.3。 7.9)。
—の引数としてbasic_string::swap()
。
—呼び出しdata()
およびc_str()
メンバー関数。
-非呼び出しconst
を除いて、メンバ関数をoperator[]()
、at()
、begin()
、rbegin()
、end()
、とrend()
。
-の形以外は、上記の用途のいずれかに続いinsert()
及びerase()
非最初の呼び出し、戻りイテレータconst
メンバ関数operator[]()
、at()
、begin()
、rbegin()
、end()
、またはrend()
。
これらのルールは非常に複雑で微妙なので、多くのプログラマがいたとしても、正確な要約を提供できるとは思えません。私ができなかった。
O(1)要件が無視されるとどうなりますか?
たとえばC ++ 11の一定の時間要件operator[]
が無視される場合、COW for basic_string
は技術的には実現可能ですが、実装するのは困難です。
COWデータのコピーを行わずに文字列の内容にアクセスできる操作には、次のものがあります。
- による連結
+
。
- を介して出力し
<<
ます。
basic_string
標準ライブラリ関数への引数としての使用。
後者は、標準ライブラリが実装固有の知識と構造に依存することが許可されているためです。
さらに、実装では、COWデータのコピーをトリガーせずに文字列コンテンツにアクセスするためのさまざまな非標準関数を提供できます。
主な複雑な要因は、C ++ 11では、basic_string
アイテムへのアクセスがデータのコピー(文字列データの非共有化)をトリガーする必要があるが、スローしないようにする必要があることです。たとえば、C ++ 11§21.4.5/ 3「スロー:なし」。そのため、通常の動的割り当てを使用してCOWデータをコピーするための新しいバッファーを作成することはできません。これを回避する1つの方法は、実際に割り当てることなくメモリを予約できる特別なヒープを使用して、文字列値への各論理参照に必要な量を予約することです。そのようなヒープでの予約と予約解除は一定の時間O(1)であり、すでに予約されている量を割り当てることは、noexcept
。標準の要件に準拠するために、このアプローチでは、個別のアロケーターごとにそのような特別な予約ベースのヒープが1つ必要になると思われます。
注:
¹ const
アイテムアクセサーは、クライアントコードがデータへの参照またはポインターを取得できるため、COWデータコピーをトリガーします。これは、非const
アイテムアクセサーなどによってトリガーされた後のデータコピーによって無効にすることが許可されていません。