2010-11-23 15 views
0

Ubuntu 10.10 gcc 4.4.4割り当てられたメモリが二重に解放されないように条件を設定する

私は割り振りと解放を実験しています。

ただし、オブジェクトが複数回解放されたときにこの問題を回避しようとしています。

しかし、私がテストすると、作成されて解放されたobjがnull状態に戻らないことがわかります。これが起こった場合、私が設定できる条件はありますか?

また、フリー後にオブジェクトをNULLに設定しようとしました。しかし、それはまだオブジェクトを解放しようとしました。

これは、あなたが重複しないことを知っているだけので、この質問への参照である:以下 freeing allocated memory

マイコード:

#include <stdio.h> 
#include "objects.h" 

int main(void) 
{ 
    obj_t *obj = NULL; 

    obj = create_object(); 

    destroy_object(obj); 

    destroy_object(obj); 

    return 0; 
} 

==

#ifndef OBJECTS_H_INCLUDED 
#define OBJECTS_H_INCLUDED 

typedef struct Obj_t obj_t; 

obj_t* create_object(); 
void destroy_object(obj_t *obj); 

#endif /* OBJECTS_H_INCLUDED */ 

==

#include <stdio.h> 
#include <stdlib.h> 

#include "objects.h" 

struct Obj_t { 
    int obj_id; 
}; 

obj_t* create_object() 
{ 
    obj_t *obj = malloc(sizeof obj); 

    return obj; 
} 

void destroy_object(obj_t *obj) 
{ 
    if(obj != NULL) { 
     printf("Object [ %d ] will be deleted\n", obj->obj_id); 
     free(obj); 
    } 
} 

==

OBJECT_FILES = objects.o main.o 
CFLAGS = -Wall -Wextra -Wunreachable-code -ggdb -O0 
CC = gcc 
TARGET = obj 

$(TARGET): $(OBJECT_FILES) 
    $(CC) $(CFLAGS) $(OBJECT_FILES) -o $(TARGET) 

main.o: main.c objects.c 
    $(CC) $(CFLAGS) -c main.c 

objects.o: objects.c 
    $(CC) $(CFLAGS) -c objects.c 

clean: 
    rm -f $(OBJECT_FILES) $(TARGET) *~ 
+0

ポインタをNULLに設定してもう一度 'フリーズ 'しようとすると、それはノーオペレーションです。ポインタを「NULL」に戻したところはどこですか? – birryree

+0

Cではなく(C++ではない)、 'obj_t * create_object();'のヘッダの宣言は、 'create_object()'が 'obj_t'を返す未定義でない空のパラメータリストを持つ関数であることを示しています。ポインタ。コンパイラは、パラメータリストの内容を伝えていないため、誤っていないことを保証することはできません。宣言に 'obj_t * create_object(void);'と書かなければなりません。そして、対称性のために 'obj_t * create_object(void){...}'を関数定義に書いてください。 –

+0

@Jon、voidパラメータについてのヒントをありがとう。 – ant2009

答えて

0

Objective-Cはreference countingです。参照カウントがゼロになるとオブジェクトを解放します。また、smart pointersを見ることもできます。

+0

私が間違っている場合は、私を許してください。しかし、スマートポインタC + +ではない? – ant2009

+0

はい、Objective-CはCのスーパーセットです。 –

+0

しかし、独自のバージョンの参照カウントを簡単に実装できます。 – JeremyP

4

関数内のポインタの値がポインタのコピーであるため、destroy_object関数内でポインタをNULLに設定することはできません。

プログラマがオブジェクトを2回解放または削除しないようにする方法は、ではありません。です。

オブジェクトが持つ参照の数を知ることができないプログラムを作成している場合は、最初に行うことはデザインを再考することです。

本当に必要な場合は、C++のshared_ptrを使用するか、Cで独自の参照カウント方式を実装します。PerlとPythonの両方で、Cの実装でそれを行います。

+0

ローカルコピーについての良い点。ありがとう。 – ant2009

+0

@ ant2009あなたは参照による呼び出しを使うことができます。この方法では、コピーではなく実際のobjを操作します。 https://www.tutorialspoint.com/cprogramming/c_function_call_by_reference.htm – Gewure

5

Mainのポインタの値は、destroy_objectへのポインタのコピーを渡すため、更新されません。必要なのはポインタへのポインタです。その後

void destroy_object(obj_t **obj) 
{ 
    if(*obj != NULL) { 
     printf("Object [ %d ] will be deleted\n", *obj->obj_id); 
     free(*obj); 
     *obj = NULL; 
    } 
} 

:これを試してみてください

destroy_object(&obj); 
1

は、通常はそれを削除する権利を有する唯一の所有者を持っているオブジェクトのための良い方法です。同時に、そのオブジェクトに1つのポインタを保持し、オブジェクトを削除した後にそのポインタをNULLに設定していることを確認してください。または、常に標準的なC++ソリューションがあります:スマートポインタ。

2

他の人が指摘したように、obj~NULLdestroy_object()に設定すると、ローカル変数が変更され、main()には影響しません。

destroy_object()デバッギング補助としてプログラマにダブルフリーズを警告したい場合は、ポイズンのコンセプトを使用できます。あなたの例では、特定の無効なobj_id値を "既に解放されています"、つまり-1と予約することができます。あなたのdestroy_object()機能その後、次のようになります。

#define OBJ_POISON (-1) 

void destroy_object(obj_t *obj) 
{ 
    if (obj != NULL) { 
     if (obj->obj_id == OBJ_POISON) { 
      fprintf(stderr, "Double-free of object @ %p detected, aborting.\n", obj); 
      abort(); 
     } 

     printf("Object [ %d @ %p ] will be deleted\n", obj->obj_id, obj); 
     obj->obj_id = OBJ_POISON; 
     free(obj); 
    } 
} 

(もちろん、これはあなたのcreate_object()機能を動作させるためにも、0のような有効な値にobj_idを設定する必要があります)。

これは、「正常に動作する」ようにダブルフリーにすることを目的としたものではなく、デバッグ中に見やすくするためのものです。

+2

poisonを得るためのポインタへの実装定義の-1のキャストの代わりに、 'static const obj_t poison;'と ' OBJ_POISON(&poison) 'などを定義してください。ポインタが一意であることが保証されます。 –

+0

実際には、-1に設定している割り当て済みの構造体では、普通のintです。明らかに、解放された記憶を読むことはまだバグですが、そこに毒の価値が残る*チャンス*があります。 – caf

関連する問題