C11標準は次のように述べています(6.2.4p2):
オブジェクトの存続期間は、プログラム実行の中で、そのオブジェクト用にストレージが確保されることが保証されている部分です。オブジェクトは存在し、一定のアドレスを持ち、最後に格納された値を存続期間を通じて保持します。オブジェクトがその有効期間外に参照された場合、動作は未定義です。ポインターの値は、それが指している (または直前の) オブジェクトがその存続期間の終わりに達すると、不確定になります。
不定値の定義は (3.19.2) です。
未指定の値またはトラップ表現
この制限には少し問題があります。中間ポインターのコピーが許容される場合は、二重リンク リストの小さな最適化が可能であることがわかりました。最適化は、次の不変条件に依存しています。
- リストの先頭要素の
prev
ポインタは不定です。 - 両端リストの場合
tail
、空のリストのポインタは不定です。
それ以外は通常の二重連結リストと同じです。これらの不変条件を使用すると、前面への挿入と前面からの削除の操作をわずかに最適化できます。具体的には (コードは片端リスト専用です):
insertToFront(e)
{
e->next = head;
e->prev = NULL;
if (head) {
head->prev = e;
}
head = e;
}
insertToFrontOptimized(e)
{
e->next = head;
if (head) {
head->prev = e;
}
head = e;
}
removeFront()
{
head = head->next;
if (head) {
head->prev = NULL;
}
}
removeFrontOptimized()
{
head = head->next;
}
他の操作は引き続き実行できます。例えば:
remove(e)
{
if (e != head) {
e->prev->next = e->next;
} else {
head = e->next;
}
if (e->next) {
e->next->prev = e->prev; // problem here
}
}
prev
head 要素を削除すると、新しい head のポインタが不確定な値に設定されるため、上記の行には問題があります。たとえば、新しいprev
ポインタは、 の後の初期化されていないポインタのコピーであるinsertToFrontOptimized()
か、 の後の解放された要素を指している可能性がありremoveFrontOptimized()
ます。
しかし、これは C 言語の観点からのみ問題があります。prev
新しい head 要素のポインターは不定値を持つことが許可されているため、リストの不変条件は壊れていません。
不確定ポインタの使用に関する制限は、この最適化を妨げますか? 回避策はありますか?