1

C++で「トランザクションストリーム」を作成する必要があります。「トランザクションストリーム」とは、処理のある時点でエラーが発生した場合に巻き戻されるストリームのことです。たとえば、ストリームのコンシューマーが何らかの理由でストリームのデータの処理に失敗した場合、そのデータを生成する前にストリームをその状態に戻す必要があります。

おそらく怠惰なストリームがこれを達成するでしょうか?これは一般的な解決策の一般的な状況ですか、それとも特定の問題に対して独自のカスタム実装を作成する必要がありますか?

4

2 に答える 2

2

さて、最初に頭に浮かぶのは、範囲インターフェース(怠惰と構成可能性のため)とトランザクションインターフェース(バックトラックのため)を組み合わせることです:

#include <iostream>
#include <stack>
#include <sstream>

struct transaction_failure {};

class transactional_istream_range {

  std::istream& stream;
  std::stack<std::streampos> states;

public:

  transactional_istream_range(std::istream& stream)
    : stream(stream) {}

  // Transaction interface.

  template<class R, class T>
  R transaction(R(*body)(T&)) {
    try {
      begin();
      R result = body(*this);
      commit();
      return result;
    } catch (const transaction_failure&) {
      rollback();
    }
    return R();
  }

  void begin() {
    states.push(stream.tellg());
  }

  void commit() {
    states.pop();
  }

  void rollback() {
    stream.seekg(states.top());
    states.pop();
  }

  // Range interface.

  bool empty() const {
    return stream.peek() == EOF && stream.eof();
  }

  char front() const {
    return stream.peek();
  }

  void pop_front() const {
    stream.ignore(1);
  }

};

次に、トランザクション範囲で動作するテンプレート関数を簡単に記述できます。

#include <cctype>

template<class R>
std::string parse_integer(R& input) {
  std::string result;
  while (!input.empty()) {
    if (std::isdigit(input.front())) {
      result += input.front();
      input.pop_front();
    } else {
      throw transaction_failure();
    }
  }
  return result;
}

int main() {
  std::istringstream stream("1234a");
  typedef transactional_istream_range tir;
  tir input(stream);
  std::string result = input.transaction(parse_integer<tir>);
  std::cout << "Result: " << result;
}

これは最初の概算です。おそらく、トランザクション関数に範囲のタイプを指定する必要があることを回避できます(つまり、parse_integerではなくparse_integer<...>)。多くの種類のレイジーストリームとレイジーアルゴリズムを範囲形式で記述するのは非常に簡単です。

これを拡張することに関しては、トランザクション処理をパラメーター化して、ユーザー指定のコミットまたはロールバック関数を呼び出すか、各タイプのロールバックを個別に実装することができます。ミックスインを使用して、範囲インターフェイスをトランザクションインターフェイスから分離することも有益な場合があります。ただし、仮想関数に頼らなければ、今のところそれを行うための良い方法は考えられません。

于 2012-07-12T22:02:08.473 に答える
1

Windowsで作業している場合は、トランザクションの形式を提供するStructuredStorageと呼ばれるものがあります。問題を別々のストリームに分割する必要があるかもしれません。

詳細は次のとおりです:http: //msdn.microsoft.com/en-us/library/windows/desktop/aa380369 (v = vs.85).aspx

または、 SQLiteFirebirdなどを使用してバックエンドのトランザクションストレージを提供することもできます。

于 2012-07-12T18:58:21.973 に答える