1

私は読んだCで負の配列インデックスは許可されていますか? 配列のインデックスに負の値を使用できることは興味深いことでした。c++11 でもう一度試してみましたが、unique_ptrそこでも動作します。もちろん、デリータは元の配列を削除できるものに置き換える必要があります。これは次のようになります。

#include <iostream>
#include <memory>

int main()
{
    const int min = -23; // the smaller valid index
    const int max = -21; // the highest valid index
    const auto deleter = [min](char* p)
    {
        delete [](p+min);
    };
    std::unique_ptr<char[],decltype(deleter)> up(new char[max-min+1] - min, deleter);

    // this works as expected
    up[-23] = 'h'; up[-22] = 'i'; up[-21] = 0;
    std::cout << (up.get()-23) << '\n'; // outputs:hi
}

メモリリークが発生する可能性が非常に低いかどうか疑問に思っています。ヒープ上に作成されたメモリのアドレス ( new char[max-min+1]) に 23 を加算するとオーバーフローし、null ポインタになることがありました。23 を減算しても配列の元のアドレスが得られますが、unique_ptrはそれをヌル ポインターとして認識する場合があります。nullのunique_ptrため、削除できない場合があります。

では、前のコードでメモリ リークが発生する可能性はありますか?それとも、スマート ポインターが安全な方法で動作するのでしょうか?

注: 実際のコードではこれを使用しません。私はそれがどのように振る舞うかに興味があります。

4

2 に答える 2

4

編集: icepackは興味深い点をもたらします。つまり、ポインター演算で許可される有効なポインター値は 2 つだけです。

§5.7 [expr.add] p5

ポインターオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は undefinedです。

そのため、new char[N] - minコードの は既に UB を呼び出しています。


現在、ほとんどの実装では、これは問題を引き起こしません。ただし、のデストラクタは次のstd::unique_ptrようになります(ここから先は回答を事前編集します)。

§20.7.1.2.2 [unique.ptr.single.dtor] p2

効果:効果get() == nullptrがない場合。そうでなければget_deleter()(get())

そうです、実際に null ポインター値を表す値に実際にマップする場合、ここでメモリ リークが発生する可能性があります (ほとんどの場合0、必ずしもそうではありません)。はい、これが単一オブジェクト用のものであることは知っていますが、配列の場合はまったく同じように動作します。

§20.7.1.3 [unique.ptr.runtime] p2

以下の説明は、プライマリ テンプレートとは動作が異なるメンバー関数についてのみ提供されています。

また、デストラクタの説明はありません。

于 2012-10-29T06:08:31.280 に答える
3

new char[max-min+1]スタックではなくヒープにメモリを割り当てます-これが標準のoperator new動作です。式max-min+1はコンパイラによって評価され、結果が3になるため、最終的にこの式はヒープに 3 バイトを割り当てることになります。ここでは問題ありません。

ただし、減算すると、minによって返される割り当てられたメモリの先頭を 23 バイト超えたポインタが返されnew、new では 3 バイトしか割り当てられていないため、これは間違いなく自分が所有していない場所を指します --> 以降は未定義の動作になります。 .

于 2012-10-29T06:16:32.553 に答える