5

これは、2 つの参照を交換するという悪い考えに関するものです。参照はリセット可能であると想定されていないため、可能であるとは想定されていません。私が知っているのはそれだけです。

私がやりたいのは、2つのポインタを交換する方法で、2つの参照を交換することです:アドレスは交換されますがデータは交換されません。推定:

int a = 0, b = 1;
int *pA = &a, *pB = &b;
std::swap(pA, pB);

現在、*pA は 1 で *pB は 0 ですが、a はまだ 0 で、b はまだ 1 です。ただし、これは参照では不可能です。

int a = 0, b = 1;
int &rA = a, &rB = b;
std::swap(pA, pB);

現在、参照は交換されていますが、元の値も交換されています。私が考えることができる唯一のことはこれです:

template <class _Ty>
struct resetable_ref {
    _Ty &ref;

    inline resetable_ref(resetable_ref &r)
        :ref(r.ref)
    {}

    inline resetable_ref(_Ty &_ref)
        :ref(_ref)
    {}

    inline resetable_ref &operator =(resetable_ref &r)
    {
        if(sizeof(resetable_ref) == sizeof(void*)) // compile-time constant (true)
            *reinterpret_cast<void**>(this) = *reinterpret_cast<void**>(&r);
        else
            memcpy(this, &r, sizeof(resetable_ref)); // optimized away as dead code
        return *this;
    }

    inline operator _Ty &()
    {
        return ref;
    }
};

int a = 0, b = 1;
resetable_ref<int> rrA(a), rrB(b);
std::swap(rrA, rrB);

ここで、a は 0 のままで、b は 1 のままで、rrA と rrB 内の参照が交換されます。やや醜い演算子 =() なしでは機能しないのは残念です。少なくとも MSVC で動作しますが、g++ がそれを受け入れるかどうかはわかりません (しかし、そうすべきだと思います)。

参照スワップ全体は、内部の別のオブジェクトへの参照で構築されたオブジェクトで使用されることになっています。それらに swap() 関数を作成したいと思います。参照の素晴らしい非nullarity機能のために、ポインターの使用を避けたいと思います。また、より優れた設計になります (resetable_ref 自体を除く)。

誰かがそれをどうやって進めるかについてより良い考えを持っていますか? これで遭遇する可能性のある互換性/未定義の動作の問題を考えられる人はいますか?

私はほとんどのコードをコンパイルせずに書きました。タイプミスに気付いた場合はご容赦ください。

編集:多くの人が質問の要点を見逃しているようです。ポインターの使い方、またはポインターを素敵なテンプレートにラップする方法さえ知っています。質問には「ハック」というタグが付けられており、それが予想されることです。それは私が尋ねたことではないので、「やらないで、ポインタを使って」のようなことを言わないでください。トピックが気に入らない場合は、回答しないでください。ただし、ポインターを使用するという理由だけで質問に反対票を投じないでください。

4

1 に答える 1

3

変更可能な参照は...ポインターではなく、参照のような暗黙的な逆参照が必要です。

template<class T>
class mutable_ref
{
public:
    mutable_ref(T& t) :p(&t)
    {}

    operator T&() { return *p; }
    operator const T&() const { return *p; }

    void swap(mutable_ref& s)
    { std::swap(p,s.p); }

private:
    T* p;
};

// just in case you also want to specialize std::swap for mutable_ref.
// not necessary, since the generic std::swap<T> use twice =, that is available.
namespace std
{
    template<class T>
    void swap(mutable_ref<T>& a, mutable_ref<T>& b)
    { a.swap(b); }
}

デフォルトの ctor がなく、参照を受け取る初期化 ctor がないことに注意してください。これにより、このクラスは null 非許容になります。

唯一の問題は、最終的な T メンバーにアクセスするには、"." であることです。オーバーライドできません。そのために何か他のものが必要です。

簡単なことは、 * と -> as... を使用することです。

T* operator->() const { return p; }
T& operator*() const { return *p; }

mutable_ref宣言内で定義される -

于 2013-03-17T17:20:59.557 に答える