Defer

C言語でもdeferを使いたい #2

c言語でdeferを実装してみよう。

まず、前回示したようにdeferを実装する構造体は次のようになる。

#include <stddef.h>
typedef struct defer_item{
  void (*deleter)(void* context);
  void *context;
}defer_item_t;

typedef struct defer_impl{
  size_t len,cap;
  defer_item_t *items;
}defer_impl_t;

そして、初期化・解消処理は次のように書ける。

#include <stdlib.h>
#include <assert.h>

// コンパイルオプション(gccなら-DDEFER_DEFAULT_CAP=XX)で
// 変更できるようにマクロを定義する。
#ifndef DEFER_DEFAULT_CAP
#define DEFER_DEFAULT_CAP 16
#endif/*DEFER_DEFAULT_CAP*/

defer_handle defer_open(){
  defer_impl_t*const impl = malloc(sizeof(defer_impl_t));
  defer_item_t*const items = malloc(DEFER_DEFAULT_CAP*sizeof(defer_item_t));
  if (!impl||!items){
    //early returnですぐに制御を戻す
    free(impl);
    free(items);
    return NULL;
  }
  // implに設定を書き込みんでいく
  impl->cap=DEFER_DEFAULT_CAP;
  impl->len=0;
  impl->items=items;//move ownership into impl
  return impl;
}

void defer_close(defer_handle d){
  assert(d);//d==NULLは明らかなコーディングミスなので落とす
  defer_item_t *const rbegin=&d->items[d->len-1];
  defer_item_t *const rend=&d->items[-1];
  for (defer_item_t* iter=rbegin;iter!=rend;iter--){
    iter->deleter(iter->context);
  }
  free(d->items);
  free(d);
}

次に開放処理を登録する関数を示す。

C言語でもdeferを使いたい #1

C言語でファイル操作やmutexを複数使っていると go言語のようにdeferを使いたくなることがある。

仮に3つ開放処理が必要な操作do_somethingをするとした場合、 C言語で書くと次のようになる。

int hoge(){
  int lock1=lock();
  if (!lock1){
    return 1;
  }

  int lock2=lock();
  if (!lock2){
    unlock1(lock1);
    return 1;
  }

  int lock3=lock();
  if (!lock3){
    unlock2(lock2);
    unlock1(lock1);
    return 1;
  }

  do_something();

  unlock(lock3);
  unlock(lock2);
  unlock(lock1);
  return 0;
}

Note