2016-10-31 26 views
5

私はQt5とQMAKE_CXXFLAGS += -std=c++1yを使って新しいプロジェクトを開始しています。私はQScopedPointerstd::unique_ptrのどちらを好むべきかはわかりません。QScopedPointerまたはstd :: unique_ptrを使用する必要がありますか?

私はsomewhereを読んでいます。QScopedPointerはそれ以上は涼しくありません。

QScopedPointerには機能がありませんunique_ptrには不足していますか? QScopedPointerを交換する際に私が望ましくないunique_ptrの機能はありますか?またはその逆?

+3

私は 'std :: unique_ptr'を使用します。 – NathanOliver

+0

私はQtスマートポインタの使用量を減らし、代わりに 'std :: shared_ptr'と' std :: unique_ptr'を使用するように移動しました。 – drescherjm

+2

標準ライブラリのクラスと別のクラスのどちらかを選択するときは、魅力的な理由がない限り、常に標準ライブラリを選択します。そのような説得力のある理由の1つは、他のタイプを使用するコードとの相互運用性が必要な場合です。 –

答えて

5

QScopedPointerは、移動セマンティクスをサポートしていないため、unique_ptrより厳密に弱いです。

それ以外の点では、その機能は非常に似ています。

移動セマンティクスは非常に便利で、間違って問題を引き起こすために誤って使用することは非常にまれです。だから彼らは無害から(より典型的に)役に立つものまで。

QScopedPointerは、既存のコードベースとの相互運用性のために使用する必要があります。それらがどれほど似ているかを考慮すると、アダプタはかなり簡単になります。

適応する必要がない場合は、unique_ptrを使用してください。


ここでは、適応について説明します。

トリッキーな部分は、QScopedPointerの2番目のパラメータです。これは、大雑把には、第2パラメータunique_ptrに相当します。

unique_ptrステートフルレターが許可されています。 QScopedPointerではそうではありません。

static void cleanup(T* pointer) 

はかなり一対一でunique_ptr

void operator()(T* pointer)const 

に対応しています。したがって:

template<class QDelete> 
struct std_deleter { 
    template<class T> 
    void operator()(T* target) const { 
    QDelete::cleanup(target); 
    } 
}; 

は、Qt deleterをstd deleterにマップします。

template<class Std_deleter> 
struct Qt_deleter { 
    template<class T> 
    static void cleanup(T* target) { 
    static_assert(std::is_empty<Std_deleter>{}, "Only works with stateless deleters"); 
    Std_deleter{}(target); 
    } 
}; 

私たちが今変換することができます:

あなたが QScopedPointerを使用したい唯一の理由についてはカバーしてい
template<class T, class D> 
QScopedPointer<T, Qt_deleter<D>> 
to_qt(std::unique_ptr<T, D>&& src) { 
    return src.release(); 
} 
template<class T, class D> 
QScopedPointer<T, Qt_deleter<D>> 
to_qt(std::unique_ptr<T[], D>&& src) { 
    return src.release(); 
} 
template<class T> 
QScopedPointer<T> 
to_qt(std::unique_ptr<T>&& src) { 
    return src.release(); 
} 
template<class T> 
QScopedPointer<T, QScopedPointerArrayDeleter> 
to_qt(std::unique_ptr<T[]>&& src) { 
    return src.release(); 
} 
template< 
    class T, class D, class R=std::unique_ptr<T, std_deleter<D> > 
> 
to_std(QScopedPointer<T, D>&& src) { 
    return R(src.take()); // must be explicit 
} 
template<class T, class R=std::unique_ptr<T>> 
to_std(QScopedPointer<T>&& src) { 
    return R(src.take()); // must be explicit 
} 
template<class T, class R=std::unique_ptr<T[]>> 
to_std(QScopedPointer<T,QScopedPointerArrayDeleter >&& src) { 
    return R(src.take()); // must be explicit 
} 

他の方法は、ステートレスであることデリータによって制限されています。いくつかのコーナーケースがあります。デフォルトのデリーターQScopedPointerはデフォルトのstd::unique_ptrに変換され、その逆もあります。

アレイの削除QScopedPointerは、unique_ptr<T[]>に変換する必要があります。逆の場合も同様です。

他のケースでは、私は単純に削除者をまとめます。理論的には、本当に素晴らしいトリックは、入ってくるDeleterが既にラップされていて、ラッピングを取り消しているかどうかを確認することですが、もしあなたのコードが多くのラウンドトリップを行っているのであれば、

+3

"既存のコードベースとの相互運用性"私はそれを "相互運用性"と呼んでいません。 'QScopedPointer'は実際にはC++ 98のコードベースを対象としています(QScopedPointerには移動セマンティクスがありません)。あなたはそれを移動することさえできないので、一般的に実装援助であり、(unique_ptrとは異なり)どのAPIにも公開されていません。そして、Qtプロジェクトは意図的に 'QScopedPointer'を改良していません - あなたはすでにそれを持っています、それは' unique_ptr'です。新しいC++ 11対応プロジェクトでは、 'QScopedPointer'ではなく' unique_ptr'を使用してください。 – peppe

+0

@peppe QScopedPointerを参照によって "返す" 1000万行のコードベースを想像し、QScopedPointer refとcrefを介してパラメータを取得します。いくつかのレガシーライブラリにはソースはありませんが、機能とテンブルを保持する必要があります。私の要点は、既存のコードベースの破壊されたhellscapeがあっても、QScopedPointerを使わないことです。 'to_qt'と' to_std'を使います。 – Yakk

0

両方のクラスの主な目的は似ていますが、それらの2つの重要な違いによって、ビジネス上の意思決定を行うことができます。

QScopedPointerには代入演算子がありません。どこでstd :: unique_ptrに代入演算子がありますか。

QTオブジェクト/コントロールを厳格にしたいが、割り当てを望まない場合は、QScopedPointerを使用してください。

+2

'const unique_ptr'には代入演算子もありません。 –

+1

しかしOPはconstを言っていない。 – Naidu

1

標準ライブラリのものと比較して、標準ライブラリにないものを使用するのはなぜですか?

私にとっては、良いプログラマがこれを行う理由は1つだけです。外部ライブラリが標準ライブラリで提供していないものを提供している場合。それは事実ですか?

今後、プログラムの移植性や更新について考慮してから決定してください。

関連する問題