0

非常に長い話を短くして、私の問題の例を挙げます。

プロパティとしてプリミティブ型へのポインターを持つクラスがあるとします。

@interface ClassOne : NSObject
{
int* aNumber
}

@property int* aNumber;

クラスがインスタンス化され、それに応じて aNumber が割り当てられ、値が割り当てられます。

ClassOne* bob = [[ClassOne alloc] init];
bob.aNumber = malloc(sizeof(int));
*bob.aNumber = 5;

次に、このタイプのクラスの別のインスタンスの aNumber 値を割り当てるために、参照によって渡されます。

ClassOne* fred = [[ClassOne alloc] init];
fred.aNumber = bob.aNumber;

次に、Fred の aNumber ポインターが解放され、再割り当てされ、新しい値 (7 など) が割り当てられます。

今、私が抱えている問題。Fred には Bob が持っていたのと同じポインターが割り当てられているので、Bob の aNumber の値は 7 になると思います。そうではありません。なぜなら、何らかの理由でポインターが解放されたが、再割り当てされていないためです (まだポインターを指している)。最初に割り当てられたのと同じアドレスで、現在は解放されています)。ただし、Fred のポインタには、別のメモリ位置に割り当てられた値 7 があります。

なぜこのように振る舞うのですか?私は何を理解していますか?C++ のように動作させるにはどうすればよいですか?

編集:そうです、新鮮な朝、私は本当に悪い、午後5時症候群の例を挙げたことがわかります. 私がやろうとしていることは、次のようなものです:

@interface classOne : NSObject
{
    int* numA;
}
@property int* numA;

@implementation...etc

numA が割り当てられ、値が割り当てられます。後で、別のスレッドで (必要なロックなどを使用して)、これが行われます。

int* numB= malloc(sizeof(int));
*numB = 5;  
free(RefToClassOne.numA);
RefToClassOne.numA = numB;

numA は解放されますが、numB が指している値が割り当てられません。これは私が望む動作です。

長い話の一部は、openGL に渡される頂点バッファーの一部の頂点数であるということです。ポインターであってはならないことはわかっていますが、座標の float* バッファーも同じように処理され、可変サイズである必要があるため、これを修正してその問題も解決したいと考えています。

4

4 に答える 4

3

あなたが誤解しているのは、(a) Objective-C では参照によって物事を渡すことができない、(b) できたとしても、ここでは役に立たないということです。

Objective-C では、値渡しのみが許可されます。オブジェクトやポインターの場合のように、渡す値自体が参照であっても、値として扱われることがあります。C++ スタイルの透過参照は存在しません。

しかし、私たちがそれらを持っていたとしましょう。この場合、それはどのように役立ちますか?aNumberインスタンス変数はまだタイプですint*。( のように) それに割り当てるときはfred.aNumber = bob.aNumber、コピーを作成する必要があります。この時点では、何が参照によって渡されたかは問題ではなく、インスタンス変数であることも問題ではありません。あなたのコードは実質的に同じです

int* bobNumber;
int* fredNumber;

bobNumber   = malloc(sizeof(int));
*bobNumber  = 5;
fredNumber  = bobNumber;

ここで、bobNumberfredNumberは異なる変数です。それらは異なる名前を持ち、メモリ内の異なる場所に存在するなど、たまたま同じ値を持っています。現在、それらが持つ値はメモリ内の別の場所への参照であるため、同等の参照です。しかし、そのうちの 1 つを変更するとどうなるでしょうか。

free(fredNumber);
fredNumber  = malloc(sizeof(int));
*fredNumber = 7;

関数の引数は値で渡されるため、それ自体freeには何もできません。fredNumberの値でのみ操作できfredNumber、参照されたメモリを解放します。これは の値と同じであるためbobNumber、 を逆参照しようとすると、この効果が見られbobNumberます。次に、 に値を代入しますfredNumberfredNumberとはメモリ内の異なる場所に存在するためbobNumber、この代入は当然 に何もしませんbobNumber。この時点で、 に代入しても、 には何も起こらないのfredNumber != bobNumberは当然です (これはdになったばかりなので、いずれにせよ無効です)。7*fredNumber*bobNumberfree

「C++のように機能させる」というあなたのコメントは奇妙であることに注意してください。私が言ったように、C++もこのようには機能しません。本当にこれを C++ で機能させたい場合は、参照インスタンス変数が必要です。

class ClassTwo {
  public:
    int*& aNumber;
    ClassTwo(int*& an) : aNumber(an) { }
};

an参照渡しする必要があることに注意してください。私はもともとそれなしでそれをやろうとしましたが、コンストラクターでコピーが作成され、同じ古い一連の問題が発生しました。

ここで、参照渡しであるかどうかにかかわらずbob、同じaNumber参照を持つため、次のようなものを構築できます。

int* shared;
ClassTwo bob(shared);
bob.aNumber = new int(5);
ClassTwo fred(bob.aNumber);
delete fred.aNumber;
fred.aNumber = new int(7);

そして、すべてが期待どおりに機能します。ただし、これは良い考えではないかもしれません。その理由の 1 つとして、shared変数に注意してください。参照は何かを参照できる必要があります。これにより問題が発生する可能性があります。参照されているオブジェクトがスコープ外になると、参照の動作が未定義になります。

于 2010-04-15T16:49:06.133 に答える
0

まあ、私が見る限り、あなたのコードはあなたが言っていることを正確に実行しています。

int へのポインターを使用することは、値を処理する最も互換性のある方法ではありません。free を適切に呼び出す必要があります。また、オブジェクト間で値を渡したいだけの場合は、NSValue オブジェクトを使用する方がはるかに簡単だと思います。

于 2010-04-15T16:38:01.813 に答える
0

これは、C++ でも同じように機能します。同等の例を次に示します。

class Bob {
    public:
    int *aNumber;
};

void wontWork() {
    Bob bob, fred;
    bob.aNumber = new int;
    *bob.aNumber = 5;
    fred.aNumber = bob.aNumber;
    delete fred.aNumber;
    fred.aNumber = new int;
    *fred.aNumber = 7;
    cout << *bob.aNumber << *fred.aNumber << endl;
}

ここで *bob.aNumber が 7 になると思いますか? するとdelete fred.aNumber、bob と fred の両方が指していたメモリが解放されました。次に、新しいメモリを指すように fred を再割り当てしましたが、bob を再割り当てしなかったため、ぶら下がっているポインターにすぎません。したがって、bob が 7 になることはありません。ポインタは int のような単純な値型であることを思い出してください。同じアドレスを指している 2 つのポインターを互いに同期させる魔法はありません。

于 2010-04-15T17:05:16.587 に答える
0

両方を同じオブジェクトを指すように設定すると、オブジェクトを解放すると、両方が指しているものが効果的に削除されるため、両方のポインターが無効になります。再割り当てするには、両方のポインターを同じ新しいオブジェクトを指すように設定して、同じ手順を繰り返す必要があります。

オブジェクトを破棄しても、そのオブジェクトを指しているすべてのポインターが自動的に更新されるわけではありません。これは、ポインターが互いに独立しており、お互いについて何も知らないためです。

問題のオブジェクトを共有するのではなく、オリジナルからクローンを作成して、各「aNumber」が独自のコピーを指すようにすることをお勧めします。

あなたが書いたC ++のようなものだと思います

フレッド=ボブ;

fred が bob のコピーを作成する場所

その場合、クラスにある種のクローン関数が必要になります。

編集:言い換え

于 2010-04-15T16:08:04.860 に答える