3

ポインターを予期する関数のパラメーター解決中に、ポインター変換ではなく参照からポインターへの変換が選択されるのはなぜですか?

template<typename T>
  class resource_ptr
  {
    public:
      operator T*()const {...} // <- C1: Convert to raw pointer for observation.
      operator T*&()     {...} // <- C2: Convert to reference to pointer, for assignment.
    ...
  };
...
void AcquireResource(resource_class *&);  // Assigns to the given pointer.
void UseResource(resource_class *);
...
resource_ptr<resource_class> rpResource;
AcquireResource(rpResource); // <- Calls C2, as expected.
UseResource(rpResource);     // <- Calls C2.  C1 would have been nice.

UseResource((resource_class*)rpResource); // <- Still calls C2. ???

この特定の設計では、C2 が書き込みアクセスを許可しているため、リソース リークを防ぐために、リソース ポインターが現在割り当てられていないことをアサートすることに注意してください。そのため、C2 は、実際に参照によってポインターが必要な場合にのみ使用することが重要です。たとえば、ポインターを割り当てる API に渡す場合などです。現状では、このデザインは壊れています。

(これらの変換は明示的な関数に置き換えることができますが、この問題を理解したいと思います。)

4

2 に答える 2

3

バージョンは、const変換対象が const の場合に使用されます。これは、通常のメンバー関数と同じように機能します。

これを読みやすくするために、名前付き変換関数を使用します。

于 2012-07-13T07:33:08.377 に答える
0

への呼び出しUseResourceは非クラス型 (ポインター型) の初期化であるため、次の句が適用されます。

8.5 初期化子 [dcl.init]

15 [...] — それ以外の場合、ソース型が (おそらく cv 修飾された) クラス型である場合、変換関数が考慮されます。適用可能な変換関数が列挙され (13.3.1.5)、オーバーロード解決 (13.3) によって最適なものが選択されます。

パラメータ type への明示的なキャストを提供するかどうかは問題ではありませんresource_class *。キャストは、初期化をcopy-initializationからdirect-initializationに変更しますが、(8.5:13 に従って) ターゲット型が非クラス型である場合、区別は無関係です。

(resource_ptr &)次に、有効な引数リストと(resource_ptr const &)(暗黙的なオブジェクト パラメーターに対して) それぞれを持つ 2 つの変換関数があります。13.3.3.2:3 は参照のバインディングに適用されるため、cv 修飾の少ない参照バインディングが、cv 修飾の多いバインディングよりも優先されます。

于 2012-07-13T14:17:25.870 に答える