実際のコードを読んだ後で編集します(上記の「注」は、実際の問題についてかなり誤解を招く可能性があります)。
を使用しようとしているコードを見ると、ノードテンプレートにTのインスタンスが含まれているため、new Node<T>;
Tのデフォルトコンストラクター(この場合は)が必要です。Tree
struct Node {
T data; // <--- instance of T, not being initialized in your code.
Node *next;
};
Tree
にはデフォルトのコンストラクターがないため、失敗します(メモには、デフォルトのコンストラクターが必要になる場所が示されています)。
それを修正する方法については、いくつかの選択肢があります。最も明白なのは、Tの実際のインスタンスを含むのではなく、Node
へのポインタまたは参照のいずれかを保持することです。T
もう1つは、Node
のコンストラクターに(おそらくconst)Tへの参照を取得させ、そのTをノードにコピーすることです。
class Node {
T data;
Node *next;
public:
Node(T const &dat) : data(dat), next(0) {}
};
これら2つのアプローチのどちらを選択するかは、かなり基本的なことです。ノードにTへのポインタ/参照を格納させる場合、ノードが存在する限り、渡されたオブジェクトが有効であり続けることを保証するためにコードを呼び出す責任があります。ノードと呼び出し元のコードは、Tの単一インスタンスへのアクセスを共有します。
対照的に、渡されたオブジェクトをノードにコピーすると、が破棄されるときにこのコピーがNode
破棄されます。ノードに渡した元のT(この場合はツリー)は、呼び出し元のコードのNode
責任を負い、そのコピーの責任を負います。
通常の場合、後者を好む傾向があります。これにより、よりクリーンなセマンティクスが提供され、データの所有権が明確に保たれます。ただし、ツリーの場合、回避できるのであれば、ツリー全体をノードにコピーしたくないでしょう。Node<shared_ptr<Tree> >
妥協点の1つは、代わりにのようなものを使用することです。shared_ptrは、少数の種類のオブジェクトと状況にのみ適したノードを作成することを避けながら、高速かつ安価にコピーを続けることができます。これはまた、元のオブジェクトへの共有アクセスを提供するポインターのみを格納していることをかなり明確にします。