unique_ptr と shared_ptr のオーバーロードメソッドはポリモーフィズムによって曖昧になります 質問する

unique_ptr と shared_ptr のオーバーロードメソッドはポリモーフィズムによって曖昧になります 質問する

私のヒントを参考にしてコーディングをしました前の質問の回答によると、Scene::addObject のオーバーロードに関する問題が発生しました。

関連する部分を繰り返し、可能な限り詳細を少なくしてこれを自己完結型にします。

  • およびInterfaceが含まれるを継承するオブジェクトの階層があります。FooBar
  • Sceneこれらのオブジェクトを所有する を所有しています。
  • Foounique_ptr私のメインでは、 はsになり、 は sBarになりますshared_ptr(前の質問で説明した理由によります)。
  • これらmainはインスタンスに渡されScene、インスタンスが所有権を取得します。

最小限のコード例はこれ:

#include <memory>
#include <utility>

class Interface
{
public:
  virtual ~Interface() = 0;
};

inline Interface::~Interface() {}

class Foo : public Interface
{
};

class Bar : public Interface
{
};

class Scene
{
public:
  void addObject(std::unique_ptr<Interface> obj);
//  void addObject(std::shared_ptr<Interface> obj);
};

void Scene::addObject(std::unique_ptr<Interface> obj)
{
}

//void Scene::addObject(std::shared_ptr<Interface> obj)
//{
//}

int main(int argc, char** argv)
{
  auto scn = std::make_unique<Scene>();

  auto foo = std::make_unique<Foo>();
  scn->addObject(std::move(foo));

//  auto bar = std::make_shared<Bar>();
//  scn->addObject(bar);
}

コメント行のコメントを解除すると、次のようになります。

error: call of overloaded 'addObject(std::remove_reference<std::unique_ptr<Foo, std::default_delete<Foo> >&>::type)' is ambiguous

   scn->addObject(std::move(foo));

                                ^

main.cpp:27:6: note: candidate: 'void Scene::addObject(std::unique_ptr<Interface>)'

 void Scene::addObject(std::unique_ptr<Interface> obj)

      ^~~~~

main.cpp:31:6: note: candidate: 'void Scene::addObject(std::shared_ptr<Interface>)'

 void Scene::addObject(std::shared_ptr<Interface> obj)

      ^~~~~

shared のコメントを外し、unique のコメントを外してもコンパイルされるので、問題はコンパイラが言うようにオーバーロードにあると解釈します。ただし、これらの型は両方とも何らかのコレクションに格納する必要があり、実際には base へのポインターとして保持されるため、オーバーロードが必要です (すべてshared_ptrs に移動されている可能性があります)。

Scene所有権を取得していること(および s の参照カウンタの増加)を明確にするため、両方を値渡ししていますshared_ptr。問題がどこにあるのかまったくわかりませんし、他の場所でこの例を見つけることができませんでした。

ベストアンサー1

あなたが遭遇している問題は、このコンストラクタですshared_ptr(13)(明示的ではない)は、同様の「基底への導出の移動」コンストラクタと同等によく一致します。unique_ptr(6)(これも明示的ではありません)。

template< class Y, class Deleter > 
shared_ptr( std::unique_ptr<Y,Deleter>&& r ); // (13)

13)shared_ptrによって現在管理されているオブジェクトを管理する を構築しますr。 に関連付けられた削除子は、r管理対象オブジェクトの将来の削除のために保存されます。はr、呼び出し後にオブジェクトを管理しません。

std::unique_ptr<Y, Deleter>::pointerが と互換性がない場合は、このオーバーロードはオーバーロード解決に参加しませんT*r.get()がヌルポインターの場合、このオーバーロードはデフォルトコンストラクタ (1) と同等です。(C++17 以降)

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; //(6)

6) 所有権を から に転送することで を構築します。unique_ptrここで は指定された削除子 (E) を使用して構築されます。u*thisu

このコンストラクターは、次の条件がすべて満たされる場合にのみオーバーロード解決に参加します。

a)unique_ptr<U, E>::pointer暗黙的にポインタに変換可能

b)U配列型ではない

c) はDeleter参照型であり、Eと同じ型であるかD、または はDeleter参照型ではなく、Eに暗黙的に変換可能である。D

非多態的なケースでは、非テンプレートムーブコンストラクタを使用するunique_ptr<T>から を構築していますunique_ptr<T>&&。オーバーロード解決では、非テンプレートが優先されます。


Sceneが sを格納していると仮定しますshared_ptr<Interface>。その場合、 をオーバーロードする必要はなくaddObjectunique_ptr呼び出しで暗黙的な変換を許可するだけで済みます。

おすすめ記事