4

訪問者のコンテキストでは、子を訪問する前に一時的に変数を設定し、後でその変数を元に戻す必要があります。私は次のコードを使用していますが、これを行うためのよりエレガントで適切な方法があると確信しています。

template <typename TYPE> class TemporaryAssignment {
protected:
    TYPE& mVariable;
    TYPE mOriginalValue;
public:
    TemporaryAssignment(TYPE& inVariable, TYPE inValue) 
        : mVariable(inVariable), mOriginalValue(inVariable) {
        mVariable = inValue;
    }
    ~TemporaryAssignment(void) {
        mVariable = mOriginalValue;
    }
};

これにより、次のようなものを書くことができます。

{
    ...
    TemporaryAssignment<string> t(myVariable, myTemporaryValue);
    visitChildren();
    ...
}
// previous value of myVariable is restored

一時割り当てオブジェクトがスコープ外になると、変数は以前の値に戻ります。これを行うためのより良い方法は何ですか?

4

3 に答える 3

6

デストラクタがスローできることを除いて、私には問題ないように見えますが、これは悪いことです。swap割り当ての代わりに元の値を使用します(編集:これは を扱いますがstd::string、 よりもユーザーフレンドリーではないクラスで発生する可能性のある問題についてはコメントを参照してくださいstring)。

コードのこの部分から少し離れれば、おそらく、一時的な値をまったく設定する必要がない方法を見つけることができます。オブジェクトの可変状態の共有は、可変グローバルが悪いのと同じ理由で悪い場合がありますが、プログラム全体を台無しにするのではなく、クラスを台無しにするだけなので、程度は低くなります。

たとえば、オブジェクト全体をコピーし、変数に新しい値を設定して、自分自身にアクセスする代わりにコピーにアクセスすることができます。明らかに、それが必ずしも可能または効率的であるとは限りません。ケースバイケースで代替案を探す必要があります。おそらく、コピーは、子に関する限り (つまり、同じ子オブジェクトを参照する) 浅くすることができます。

使用法に関しては、次のようなタイプを推測できます (テストされていないコード):

template <typename T, typename ARG>
TemporaryAssignment<T> temp_value(T &var, ARG &&newvalue) {
    return TemporaryAssignment(var, std::forward<ARG>(newValue));
}

使用法:

auto t = temp_value(myVariable, myTemporaryValue);

次に、TemporaryAssignment の移動コンストラクターが必要です。

template <typename TYPE> class TemporaryAssignment {
    // change data member
    TYPE *mVariable;
    TYPE mOriginalValue;
public:
    TemporaryAssignment(TYPE &inVariable, TYPE inValue) 
    : mVariable(&inVariable), mOriginalValue(std::move(inVariable)) {
        *mVariable = std::move(inValue);
    }
    TemporaryAssignment(TemporaryAssignment &&rhs) {
        mOriginalValue = std::move(rhs.mOriginalValue);
        mVariable = rhs.mVariable;
        rhs.mVariable = 0;
    }
    ~TypeAssignment() {
        using std::swap;
        if (mVariable) {
            swap(*mVariable, mOriginalValue);
        }
    }
    // can't remember whether this is needed
    TemporaryAssignment(const TemporaryAssignment &) = delete;
    TemporaryAssignment &operator=(const TemporaryAssignment &) = delete;
    TemporaryAssignment &operator=(TemporaryAssignment &&) = delete;
};

使い方が代入に見えるようにoperator=forを指定しようとちょっと考えたのですが、うまくいきませんでした。TemporaryAssignment

auto t = (temporary(myVariable) = myTemporaryValue);

もっともらしいですが、次の意味があるため、おそらく定義したくないでしょうTemporaryAssignmentoperator=

t = otherTemporaryValue;

必ずしも明確ではなく、おそらく許可されるべきではありません。から返される 2 番目のクラスを使用して、その からtemporary返される可能性があります。TemporaryAssignmentoperator=

于 2012-11-14T17:13:18.750 に答える
2

swapTYPEメンバーがある場合std::string、クラッシュの問題も発生する可能性があるため、最適な解決策ではありません。次のようないくつかの方法を使用できると思います。

char buffer[sizeof(TYPE)];
memcpy(buffer, &mVariable, sizeof(TYPE));
memcpy(&mVariable, &mOriginalValue, sizeof(TYPE));
memcpy(&mOriginalValue, buffer, sizeof(TYPE));
于 2012-11-15T07:53:05.547 に答える
0

スティーブジェソップからの答えに追加します。RIIA(またはRAII)の観点からは、クラスのデストラクタは、リソースを解放するだけのリソース(メモリ)を取得してしまう可能性があります。これを回避するには、適切なタイミングで適切なオブジェクトを指すmyVarを使用することを考えることができます。これにより、新しいオブジェクトは構築時または取得時にのみ適切に作成され、リリース時に削除とポインターの再割り当てのみが行われます。 。

于 2012-11-14T18:18:57.020 に答える