0

ポインターを作成し、performSelectorInBackground:を使用して新しいスレッドに渡すObjective-Cメソッドがあります。問題は、スレッド内からそれに関連付けられたメモリを解放したいので、ポインタのアドレスをスレッドに渡す必要があることです。私が抱えている問題は、新しいスレッドが起動されると、呼び出し元のメソッドが終了し、ポインターがスコープ外になることです。スレッドがポインタのアドレスを受け取ることができる場所にそれを十分長く保つにはどうすればよいですか?

もちろん、メインスレッドで「pointerTest」メソッドを呼び出すだけで、これはすべて機能します。

これが私のコードです:

-(void)pointerTest:(NSValue*)pointer
{   
    void **p = (void**)[pointer pointerValue];
    fprintf(stderr,"p was %s\n",(char*)(*p)); //prints "Hello There!"
    free(*p);
    *p = NULL;
}

さて、メインスレッドで:

-(IBAction)doTest:(id)sender
{
    char *str = "Hello There!";

    void *p = malloc(strlen(str)+1);
    strcpy(p, str);

    //this works
    //[self pointerTest:[NSValue valueWithPointer:&p]];

    //this fails
    [self performSelectorInBackground:@selector(pointerTest:) withObject:[NSValue valueWithPointer:&p]];

    if(!p){
        fprintf(stderr,"p was NULL!\n");
    }else{
        fprintf(stderr,"p was NOT NULL: %s\n",p);
    }
}

アップデート:

このコードは、pointerTest:にポインターを渡さないと、pointerTest:内からpを解放できないことを示しています。

-(void)pointerTest:(NSValue*)pointer
{   
    void *p = (void*)[pointer pointerValue];
    fprintf(stderr,"p was %s\n",(char*)p); //prints "Hello There!"
    free(p);
    fprintf(stderr,"p was %s\n",(char*)p); //STILL prints "Hello There!"
    *p = NULL;
    fprintf(stderr,"p was %s\n",(char*)p); //prints "(null)"
}

さて、呼び出しメソッドで:

//I pass p, NOT a pointer to p
[self pointerTest:[NSValue valueWithPointer:p]];

if(p){
    //p is not NULL, and in fact I can print its value
    fprintf(stderr,"p was NOT NULL: %s\n",p);
}

ただし、pの代わりにpにポインターを渡すと、pointerTest内から期待どおりにその値を解放できます。pointerTestから戻ると、呼び出し元のメソッドでpがNULLになります。

4

1 に答える 1

3

malloc[なぜC文字列をObjective-Cと混合しているのかは尋ねませんが、実験していると思います。そうすること自体に問題はありません。このような状況では珍しいことです。]

ポインタをポインタに渡す必要はまったくありません。

ポインタボックス名前です。一部のボックスには、文字、一部の従業員レコードなど、および一部のボックス名(他のボックスの)が含まれています。必要なサイズのボックスを見つけてその名前を返します。整数値を渡すのと同じようにそれを渡すことができます。文字を含むボックスの名前を含むボックスの名前を渡す必要はありません...malloc

またmalloc、C文字列の末尾のNUL文字を許可する必要がある場合は、文字列の長さに1を追加します。

試す:

- (void) pointerTest:(NSValue *)pointer
{   
   void *p = (void *)[pointer pointerValue];
   fprintf(stderr,"p (%p) was %s\n", p, (char *)p);

   free(p);
}

- (IBAction) doTest:(id)sender
{
   char *str = "Hello There!";

   void *p = malloc(strlen(str)+1); // allow for NUL
   fprintf(stderr,"p is %p\n", p);
   strcpy(p, str);

   // this works
   // [self pointerTest:[NSValue valueWithPointer:p]];

   // and so does this
   [self performSelectorInBackground:@selector(pointerTest:) withObject:[NSValue valueWithPointer:p]];

   if(!p)
   {
      fprintf(stderr,"p was NULL!\n");
   }
}

どちらかでまとめる必要はないことに注意してくださいp。Objective NSValue-Cメソッドにポインタ値を渡すことには何の問題もありません。

HTH

コメント後

ポインタの有効性と、ポインタが参照するメモリにたまたまある可能性のあるものとを混同しています。

ポインタが参照するメモリが解放されます。呼び出し後、ポインタ値は無効になりますfree-ダングリングポインタです。

現在ダングリングポインタ値によって参照されているメモリは、いつでも再利用できます。たまたまfprintf、メモリがまだ再利用されていないため、古い内容が表示されます。メモリを解放しても、メモリはクリアされません。

変数へのストアはNULL、ダングリングポインターを削除することを目的としています。これを行うことは一般的には良い習慣かもしれませんが、短命の変数のアドレスを取得して別のメソッドに渡すことは、ダングリングポインタ。それで、ボックスAがそれ自体で解放されたので、ボックスAへのダングリングポインタを使用して、ボックスAからボックスBへのダングリングポインタをクリーンアップしようとすることになりました...別の方法で説明してみましょう;-)

この場合、pに属するローカル変数(ボックス)へのポインターを作成しました。完了するdoTestとすぐに、システムは使用されていたボックスをフリーボックスパイル(この場合はスタック)にdoTest返し、ポインターがぶら下がっています。 p; その後、元のコードがそれを介してそのボックスpointerTestに格納しようとしたときに、ダングリングポインタが問題になりました。NULL

于 2012-09-28T21:26:37.160 に答える