どのような状況下で、この種のコードをC ++で使用しますか?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
どのような状況下で、この種のコードをC ++で使用しますか?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
回答:
ポインターが指しているオブジェクトではなく、ポインターを変更する必要がある場合は、ポインターを参照で渡します。
これは、ダブルポインターが使用される理由に似ています。ポインターへの参照を使用する方が、ポインターを使用するよりも少し安全です。
delete
たり、そのポインターをメモリ内の他の場所に再バインドしたりすることはできませんか?それとも私はそれを間違っていましたか?
[]
演算子をオーバーロードするでしょう。これに対する可能な(そして実際には自然な)署名の1つはですconst T &operator[](size_t index) const
。しかし、あなたも持つことができますT &operator[](size_t index)
。あなたは同時に両方を持つことができます。後者では、次のようなことができますmyArray[jj] = 42
。同時に、データへのポインタを提供していないため、呼び出し元はメモリを乱用することはできません(たとえば、誤って削除してしまうなど)。
C ++プログラマの50%は、削除後にポインタをnullに設定することを好みます。
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
参照がなければ、ポインターのローカルコピーのみが変更され、呼び出し元には影響しません。
paranoid_delete
いましたが、パピーはその名前をに変更しましたmoronic_delete
。彼はおそらく他の50%に属しています;)とにかく、後のnullへのポインターの設定delete
はほとんど役に立ちません(とにかくスコープ外に出る必要があるため)、「解放後の使用」バグの検出を妨げることが多いです。
delete
は一般的に愚かだと思っているようです。子犬、私はいくつかグーグルをしました、なぜ削除が完全に役に立たないのかわかりません(多分私も恐ろしいグーグルです;))。もう少し説明したり、リンクを提供したりできますか?
デビッドの答えは正しいですが、それでもまだ抽象的な場合は、2つの例を示します。
解放されたすべてのポインターをゼロにして、メモリーの問題を早期にキャッチしたい場合があります。あなたがするCスタイル:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
C ++で同じことをするには、次のようにします。
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
リンクリストを扱う場合-多くの場合、次のノードへのポインタとして単に表されます:
struct Node
{
value_t value;
Node* next;
};
この場合、空のリストに挿入すると、結果はNULL
もうポインターではないため、着信ポインターを変更する必要があります。これは、関数から外部ポインターを変更する場合であるため、シグニチャーにポインターへの参照があります。
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
この質問には例があります。
このようなコードを使用して、渡されたポインターにメモリを割り当て、そのサイズを返す関数を提供する必要がありました。これは、会社の「オブジェクト」がSTLを使用しているためです。
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
それは良いことではありませんが、ポインタは参照によって渡される必要があります(またはダブルポインタを使用します)。そうでない場合、メモリリークが発生する値によって渡される場合、メモリはポインタのローカルコピーに割り当てられます。
たとえば、パーサーが正しく認識した最後の文字の後ろにポインターを押し込むことが想定されている場合に、パーサー関数を記述してそこにソースポインターを渡します。ポインターへの参照を使用すると、関数が元のポインターを移動してその位置を更新することが明確になります。
一般に、ポインタを関数に渡し、元のポインタに影響を与えずにそのコピーを移動するのではなく、元のポインタを別の位置に移動させる場合は、ポインタへの参照を使用します。
これが必要になる別の状況は、ポインタのstlコレクションがあり、stlアルゴリズムを使用してそれらを変更したい場合です。C ++ 98でのfor_eachの例。
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
そうでない場合、changeObject(Object * item)シグネチャを使用すると、元のポインタではなく、ポインタのコピーが得られます。