2016-01-03 3 views
13

私はGCCの拡張子__attribute__((cleanup))は、少なくともいくつかのケースでは良いアイデアだと思うが、私はそれを使用する方法を見つけることができませんいい意味で。私がやっていることは、まだ本当に迷惑に見える。GCCとclang __attribute __((クリーンアップ))とポインタ宣言を使用する良いと慣用方法

私はあまり型に#define _cleanup_(x) __attribute__((cleanup(x))をやって多くのコードを見ましたが、そこなどfreeまたはclosedirfclose、などの標準関数を渡すことが方法はありますか?

私はちょうど書くことはできません見ての通り:、かなり迷惑なんだ

static void free_char(char **ptr) { free(*ptr); } 
__cleanup__((free_char)) char *foo = malloc(10); 

:クリーンアップコールバックがchar**ポインタを受け取ることになりますので

__attribute__((cleanup(free))) char *foo = malloc(10); 

、と私はいつものようなものを記述する必要があります最も厄介な部分は、あなたが必要とするすべてのタイプに対してこのようなクリーンアップ関数を定義することです。なぜなら、明らかにそれをvoid **のために定義することはできないからです。これらの事を避ける最善の方法は何ですか?

+6

あなたは '__attribute __((cleanup))'が**良いアイデアではないと言ってもいいでしょう。 – user3386109

+7

デストラクタが必要な場合は、デストラクタを見つける場所を知っています。 –

+0

@ user3386109、それは良いアイデアだと思いますが、実現は少し壊れています。あるいは、私が理解できないものがあるかもしれないので、私はそれを求めています。 – coredump

答えて

8

ここ__attribute__((cleanup))の上に汎用スマートポインタ(unique_ptrshared_ptr)を構築するライブラリがあります:https://github.com/Snaipe/libcsptr

それはあなたがこのような高いレベルのコードを記述することができます:

#include <stdio.h> 
#include <csptr/smart_ptr.h> 
#include <csptr/array.h> 

void print_int(void *ptr, void *meta) { 
    (void) meta; 
    // ptr points to the current element 
    // meta points to the array metadata (global to the array), if any. 
    printf("%d\n", *(int*) ptr); 
} 

int main(void) { 
    // Destructors for array types are run on every element of the 
    // array before destruction. 
    smart int *ints = unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int); 
    // ints == {5, 4, 3, 2, 1} 

    // Smart arrays are length-aware 
    for (size_t i = 0; i < array_length(ints); ++i) { 
     ints[i] = i + 1; 
    } 
    // ints == {1, 2, 3, 4, 5} 

    return 0; 
} 

しかし、慣用では?まあ、上記は確かに慣用的なC++に近いです。それほどCではない。この機能は、GCCとClangで主にサポートされています。これはC++コンパイラも備えているため、追加料金なしでCフロントエンドでRAIIマシンを使用することができます。これは、このようにCを意図したものとして書くことをお勧めしません。 C++コンパイラが実際にはであるにもかかわらず、実際にはを使用しているにもかかわらず、ある程度依存しています。

私がいたのであれば、実際に純粋なC言語で実行できるオートリリースプールなどを実装することを検討していたと思います。リソースを解放する必要があるかどうかによって異なります。記憶のために、あなたは通常すぐにクリーンアップすることなく生きることができます。

5

__attribute__((cleanup(free)))は書き込むことはできませんが、種類ごとにfreeクリーンアップ機能を記述する必要はありません。それは醜いですが、あなたはこれを書くことができます。

static void cleanup_free(void *p) { 
    free(*(void**) p); 
} 

は、私が最初にこのin the systemd codebaseを見ました。

その他の機能の場合は、一般的に、で使用するために間接レベルの余分なレベルのラッパーを作成する必要があります。 systemddefines a helper macro for thisall over the place使用される

#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)    \ 
    static inline void func##p(type *p) {     \ 
      if (*p)           \ 
        func(*p);        \ 
    }              \ 
    struct __useless_struct_to_allow_trailing_semicolon__ 

、例えば

DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); 

#define _cleanup_pclose_ __attribute__((cleanup(pclosep))) 
関連する問題