Javaから来たC++は初めてです。
Javaでは、すべての変数(プリミティブを除く)は基本的にポインターです。彼らは「保持」しているもののアドレスを保持しています。
したがって、すべてのJavaデータ構造は参照によってデータを保存します。値によって保存することもできます。つまり、保存したアイテムのコピーを保存して返すこともできますが、追加の作業が必要であり、ネイティブではありません。言語に。
たとえば、コレクションArrayList
、HashSet
、および単純な配列はすべて、実際のアイテムではなく、それらが「保存」するアイテムのアドレスを保存します。
ただし、C++では、選択肢があります。コンテナークラスを実装するときは、値または参照によってユーザーアイテムを格納して返すことができます。
たとえば、ここに私が書いた簡単なStack
クラスがあります(無関係なものは省略):
template <typename T> class Stack {
public:
Stack(...) : ... { }
void Push(const T& item) {
if(size == capacity - 1)
enlargeArray();
data[indexToInsert++] = &item;
size++;
}
const T& pop() {
const T& item = *data[indexToInsert - 1];
data[indexToInsert - 1] = 0;
indexToInsert--;
size--;
return item;
}
int getSize() const {
return size;
}
private:
const T** data;
int indexToInsert;
int size;
int capacity;
void enlargeArray() {
// omitted
}
};
このデータ構造は、参照によってデータを受け取り、返します。 Push
はconst参照を受け取り、pop
はconst参照を返します。バッキング配列は、オブジェクトではなくポインタの配列です。
ただし、Push
も次のようになります。
void Push(T item) {
if(size == capacity - 1)
enlargeArray();
data[indexToInsert++] = item;
size++;
}
また、pop
は、const T&
ではなく、T
を返す可能性があります。
私の質問は、C++で推奨されるアプローチは何ですか? Is推奨されるアプローチはありますか? 「コンテナ」クラスを実装する場合、通常どのアプローチを取るべきですか?
まず、おそらくコンテナークラスを実装しないでください。 95%の確率で標準ライブラリに含める必要があります。学びたいだけの場合、または5%以内の場合は、続けてください。
テンプレートを定義する場合は、ユーザーに決定を任せます。ユーザーは以下を使用できます。
Stack<Foo>
値によって必要な場合。 Stack<Foo*>
ポインタで必要な場合。 Stack<std::unique_ptr<Foo>>
自分自身をクリーンアップするポインタが必要な場合。
どちらを使用するかを選択するときは、別のことをする十分な理由がない限り、デフォルトで値を使用する必要があります。スタッククラス内では、すべてを値で格納します。テンプレートの使用で間接参照が必要な場合は、T =ポインター型を使用できます。
コードを見る:
void Push(const T& item) {
if(size == capacity - 1)
enlargeArray();
data[indexToInsert++] = &item;
size++;
}
それはできません。 &item
は、渡されたものへのポインターを記録します。ただし、ポインターが有効な期間はわかりません。プッシュ終了直後は無効になる場合があります。その場合、無効な場所へのポインタを保存しました。一般に、ポインタが有効であるとは限りません。代わりにアイテムをコピーする必要があります。
私の質問は、C++で推奨されるアプローチは何ですか?推奨されるアプローチはありますか? 「コンテナ」クラスを実装する場合、通常どのアプローチを取るべきですか?
C++では、次の方法でオブジェクトを保持できます。
これらはそれぞれ、さまざまな状況で有効であり、オブジェクトの所有権、寿命の管理、および多態性の振る舞いに関してさまざまな制約を課します(つまり、推奨されるアプローチはありません-それらの多くがあります:)):
保存を使用値によるの場合:
保存を使用参照によりの場合:
生のポインタによる格納を使用する場合:
スマートポインタによる格納を使用する場合:
これらすべてをサポートするには、おそらく、クライアントコードで、格納された型によってクラスをテンプレート化し、必要に応じて入力する必要があります。
コンテナがオブジェクトを「所有」していて、それらが基本クラスであるかどうかに依存します。
コンテナーがオブジェクトを所有していない場合は、ポインターを使用してダングラーに注意する必要があります(オブジェクトが破棄されるときに、コンテナーがオブジェクトへのポインターを保持していないことを確認してください)。
コンテナーがオブジェクトを所有し、基本クラスでない場合は、値で格納する必要があります。
それ以外の場合(コンテナは所有し、サブクラスがあります)std::unique_ptr
を使用して保存し、保存時にスライスが発生しないようにし、適切に破棄する必要があります。