0

2 つの関数を定義しました。

1)。

template<class T> inline
void swap(T &first, T &second)
{   
    if (&first != &second)
    {
        T tmp = first;
        first = second;
        second = tmp;
    }
}

2)。

template<typename T>
inline void SwapMe(T *first, T *second)
{
    if(*first != *second)
    {
        T tmp = *first;
        *first = *second;
        *second = tmp;
    }
}

どちらの実装が優れているか (最初の実装は std::swap() に等しい) ?

4

4 に答える 4

1

最初のバージョンは、参照によって渡される変数または値によって渡される変数を使用する方が優れています。

2つ目は、値へのポインターに適しています。

参照はポインタとは異なる動物であるため、これらは異なります。

于 2013-01-23T04:38:00.513 に答える
1

あなたの (つまり ) とほぼ同じことを行う標準関数テンプレートがあり、あなたの(つまり) とほぼ同じことを行う標準関数テンプレートがあります。swapstd::swapSwapMestd::iter_swap

どちらも実際には「優れている」わけではなく、それぞれに用途があります。どちらも他方を使用して実装できますが、標準iter_swapでは で定義されているswapためswap、より基本的な操作と考えられます。swap独自の型に対して ADL オーバーロードを行うということです。

あなたのコードでは、*first != *secondあなたのテストSwapMeは非常に疑わしいです。が必要Tであり、一部のタイプでは非常に遅くなる可能性があるためoperator!=、最適化はそれほど多くないため、一般的なケース (オブジェクトが等しくない場合) に大きなコストが追加されます。!=さらに、型の定義によっては、T等しいオブジェクトをスワップすると効果があるはずです (vectorたとえば、 の場合、容量は等価比較に参加しませんが、またはを使用してスワップする交換されます)。現時点ではもっと悪いですが、それは意図したものではないと思います:-)std::swapvector::swapSwapMe

実際、関数内のそのようなテストswapは疑わしいものです。ほんのわずかであっても、一般的なケースの速度が低下する傾向があるためです。しかし、テストを同じにすると、テストが存在するかどうかは、パラメーターの型がどうあるべきかとは別の議論になります。

于 2013-01-23T07:34:04.723 に答える
1

ケース 2 が危険だとは誰も言いません。コードに NULL ポインターが含まれている場合、プログラムがクラッシュしますか: SwapMe (NULL, NULL)

于 2013-01-23T05:31:12.917 に答える
1

私はそれが好きなので、最初のものを除いて、どちらも優れていません。関数が引数を変更する可能性があることを呼び出し側で明示する必要があると考えているため、2 番目の方法を好む人もいます。関数が何をするのかわからない場合は関数を呼び出すべきではなく、swap の場合のように、関数が何をするかは名前で明らかであるべきだと私は考えています。また、C++ での生のポインターの唯一の目的は、非所有、再配置可能、または無効化可能な参照であることも念頭に置いています。必要に応じて、標準ライブラリのような独自のメモリ管理クラスを実装する場合を除きます。

于 2013-01-23T04:46:55.737 に答える