RAIIの代用

C++だとRAIIでリソースの後始末ができる。CだとRAIIが使えないが代案を考えてみた。エラーコードが雑なのは気にしないで。

ありがちなもの。

int func(char const* filename) {
  FILE *fout = fopen(filename, "a+");
  if (fout == NULL) {
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    fclose(fout);
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    fclose(fout);
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  fclose(fout);
  return 0;
}

リソースの後始末が面倒だよね。

もう一つのありがちなもの。

int func(char const* filename) {
  int ercd = 0;
  FILE *fout = fopen(filename, "a+");
  if (fout == NULL) {
    ercd = -1;
    goto ON_EXIT;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    ercd = -1;
    goto ON_EXIT;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    ercd = -1;
    goto ON_EXIT;
  }
  fprintf(fout, "Logging ...\n");
ON_EXIT:
  fclose(fout);
  return ercd;
}

ercdって変数は要らないよね。

思いついたもの。

static int func_impl(FILE *fout) {
  if (fout == NULL) {
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  if (do_something()) {
    return -1;
  }
  fprintf(fout, "Logging ...\n");
  return 0;
}
int func(char const* filename) {
  FILE *fout = fopen(filename, "a+");
  int const ercd = func_impl(fout);
  fclose(fout);
  return ercd;
}

まともなコンパイラならfunc_implをインライン化するよね。