17

そのため、C++ コンテナ オブジェクトと文字列を永続メモリに割り当てることができる、優れた永続アロケータ クラスpersistent_alloc<T>があります。このメモリは、プログラムの 1 回の実行から次の実行まで保持できる mmaped ファイルに支えられています。

私の問題は、永続オブジェクトと非永続オブジェクトを混在させたい場合に発生します。たとえば、私は

typedef std::basic_string<char, std::char_traits<char>, persistent_alloc<char>> pstring;

pstring a, b, c;
std::string x, y, z;

次のようなことができるようになりたいです。

if (a == x)
    a = y;
c = z + b;

pstringなどですが、とstd::stringは無関係なタイプであるため、デフォルトでは機能しません。比較に関する限り、次のように定義できます。

template<typename Alloc1, typename Alloc2> inline bool
operator==(const std::basic_string<char, std::char_traits<char>, Alloc1> &a,
           const std::basic_string<char, std::char_traits<char>, Alloc2> &b)
{
    return strcmp(a.c_str(), b.c_str()) == 0;
}

...これで、文字列が等しいかどうかを比較できます。しかし、すべての操作にこれらを追加するのは面倒に思えます-標準ライブラリによって提供される必要があるようです。さらに悪いことに、代入演算子とコピー コンストラクターはメンバーでなければならず、このようなグローバル インライン関数として定義することはできません。

これを行う合理的な方法はありますか?それとも、アロケータを便利にサポートするために、標準ライブラリ全体を効果的に書き直す必要がありますか?

4

1 に答える 1

8

これを処理する方法はありますが、ボックスの外側を少し考える必要があります。必要なのは、std::stringとアロケータ文字列の両方から暗黙的に構築可能な中間型です。

現在、C++委員会の前にそのようなことについての提案があります。これは、すでに存在するGoogleが構築したApacheライセンスの実装に基づいています。それは呼ばれbasic_string_refます; これは、基本的に文字列の最初の文字へのポインタであり、文字列の長さを表すサイズであるテンプレートクラスです。メモリを管理しないという意味では、真のコンテナではありません。

これはまさにあなたが必要とするものです。

basic_string_ref特定の文字タイプおよび特性タイプについては、アロケータにstd::basic_string 関係なく、暗黙的に構築可能です。

すべての比較演算子は、で定義できますbasic_string_ref。暗黙的に構築可能であるためstd::basic_string(そして事実上自由に構築可能であるため)、異なる割り当ての文字列間の比較に対して透過的に機能します。

割り当てを行うのはかなり難しいですが、実行可能です。一連の変換が必要です。

a = pstring{basic_string_ref{y}};

もちろん、最も美しいコードではありません。のコピーコンストラクタと代入演算子をstd::basic_stringアロケータに依存しないように変更することをお勧めします。しかし、それは実行不可能なので、これは本当に次善の策です。テンプレート関数でラップすることもできます。

template<typename DestAllocator, typename SourceAllocator, typename charT, typename traits>
std::basic_string<charT, traits, DestAllocator> conv_str(const std::basic_string<charT, traits, SourceAllocator> &input)
{
  return std::basic_string<charT, traits, DestAllocator>{basic_string_ref<charT, traits>{y}};
}

もちろん、それができれば、次のようにすることができます。

template<typename DestAllocator, typename SourceAllocator, typename charT, typename traits>
std::basic_string<charT, traits, DestAllocator> conv_str(const std::basic_string<charT, traits, SourceAllocator> &input)
{
  return std::basic_string<charT, traits, DestAllocator>{y.begin(), y.end()};
}

これがの一部にすぎstd::basic_stringないので、回避策は必要ありません。しかし、そうではありません。

于 2012-05-10T20:38:34.567 に答える