Accelerated C++ Chapter 10

どもです。
腰の具合が思ったよりも悪く,歩くと結構痛いですが,そこは
断固桜木で,いろいろと用事を済ませてきましたよっと。

メモ

  • 関数へのポインタ
void f(void);
// ...
void (*p_f)(void);
p_f = f;  // これと,
p_f = &f; // これは同じこと。
// 呼び出し
p_f();    // これと
(*p_f)(); // これは同じ事。
// でも,ポインタであることをわかりやすくするために,
// (*p_f)() の方がいいかも。と,CUnit のソースを眺めていて思いました。
    • 関数へのポインタの定義は大変
      • typedef を使おう。
typedef void (*fp)(void);
fp func_ptr; // func_ptr は,シグニチャとして,void fp(void) をもつ関数へのポインタ。
      • 読み方は,K&R に詳しい。かった記憶がある。

void (*fp)(void) の場合は,fp is a pointer to a function, expecting void, returning void.
だったはず。

  • ファイルの扱い
    • 読み込み
      • ifstream
        • ifstream("file.txt");
        • スコープ抜けたら自動でファイルが閉じられる。
    • 書込み
      • ofstream
    • 読み書き
      • fstream
  • ポインタの扱い
    • ある関数の中で,ローカル変数のへのポインタを返すとか危険よ。参照もだけど。
      • static, dynamic allocation
  • 動的メモリ割り当て
    • new, delete, delete[]
T *p = new T();
p = new T; // デフォルト初期化
delete p;
// 配列
p = new T[n];
delete[] p;
    • 要するに,new なら delete, new ならdelete
↑は,「要するに,new なら delete, new[] なら delete[]。」と書いてます。
はい来ました。[] 単体なら消えないが,new[] と書くと,[] が消える。
はてなの仕様?
    • 自分で管理するのは大変。必ずどこかに抜けが生じる。オレだけか?
  • Input / Output
    • cin
      • stdin
    • cout
      • stdout
    • cerr
      • stderr
    • clog
      • ログ用。バッファリングされる。

Exercises

なげーどー。

Exercise 10-2

median.hh

#ifndef GUARD_MEDIAN_H
#define GUARD_MEDIAN_H

#include <vector>
#include <stdexcept>
#include <algorithm>
#include <iostream>

template<class Iter>
typename std::iterator_traits<Iter>::value_type
median(Iter beg, Iter end)
{
  typename std::iterator_traits<Iter>::difference_type size = std::distance(beg, end);

  if (beg == end) {
    throw std::domain_error("median on the empty container");
  }
  else if (size == 1) {
    return *beg;
  }

  typedef typename std::iterator_traits<Iter>::value_type ValType;
  std::vector<ValType> vec(beg, end);
  std::sort(vec.begin(), vec.end());
  size_t mid = size / 2;

  if (size % 2 == 0) {
    return (*(vec.begin() + mid - 1) + *(vec.begin() + mid)) / 2;
  }
  else {
    return *(vec.begin() + mid);
  }
}

#endif  // GUARD_MEDIAN_H
Exercise 10-4, 10-5
  • String_list.hh
#ifndef GUARD_STRING_LIST_H
#define GUARD_STRING_LIST_H

#include <string>
#include <cstddef>
#include <memory>

////////////////////////////////////////////////////////////////////////////////
class String_list_node {
  friend class String_list;
  friend class String_list_iterator;
private:
  String_list_node(const std::string& s) : str_(s), next_(0), prev_(0) {}

  std::string str_;
  String_list_node *next_, *prev_;
};

////////////////////////////////////////////////////////////////////////////////
class String_list_iterator {
public:
  String_list_iterator(String_list_node *node) : node_(node) {}
  std::string* operator->() { return &(node_->str_); }
  std::string& operator*() { return node_->str_; }
  String_list_iterator& operator++() {
    node_ = node_->next_;
    return *this;
  }
  String_list_iterator& operator--() {
    node_ = node_->prev_;
    return *this;
  }

  bool operator==(const String_list_iterator arg) { return node_ == arg.node_; }
  bool operator!=(const String_list_iterator arg) { return node_ != arg.node_; }

private:
  String_list_node *node_;
};

////////////////////////////////////////////////////////////////////////////////
class String_list {
public:
  typedef size_t size_type;
  typedef std::string value_type;
  typedef String_list_iterator iterator;

  String_list() : head_(0), tail_(0), size_(0) {}
  String_list(const String_list& arg);
  String_list(size_t n, const std::string& s);
  ~String_list();

  String_list& operator=(const String_list& arg);

  void push_back(const std::string& s);
  size_type size() const { return size_; }
  bool empty() const { return size_ == 0; }

  iterator begin() { return String_list_iterator(head_); }
  iterator end() { return String_list_iterator(tail_); }

private:
  String_list_node *head_, *tail_; // tail_ is a sentinel.
  size_type size_;
};

#endif  // GUARD_STRING_LIST_H
  • String_list.cc
#include <string>
#include <iostream>
#include <cassert>
#include <cstddef>

#include "String_list.hh"

using namespace std;

String_list::String_list(size_t n, const std::string& s) : head_(0), tail_(0), size_(0)
{
  head_ = new String_list_node(s);
  tail_ = head_;
  String_list_node *prev = head_, *tmp;
  --n;
  for (size_t i = 0; i < n; ++i) {
    tmp = new String_list_node(s);
    prev->next_ = tmp;
    tmp->prev_ = prev;
    prev = tmp;
    tail_ = tmp;
  }
  tmp = new String_list_node(string("dummy"));
  tmp->prev_ = tail_;
  tail_->next_ = tmp;
  tail_ = tmp;
  size_ = n + 1;
}

String_list::String_list(const String_list& arg)
{
  size_ = arg.size_;
  if (size_ == 0) {
    head_ = tail_ = 0;
    return;
  }
  // Copy each node
  const String_list_node *from = arg.head_;
  head_ = new String_list_node(from->str_);
  size_t n = size_ - 1;
  String_list_node *p = 0, *pp = head_;
  from = from->next_;
  for (size_t i = 0; i < n; ++i) {
    p = new String_list_node(from->str_);
    pp->next_ = p;
    p->prev_ = pp;
    pp = p;
  }
}

String_list::~String_list()
{
  if (head_ == 0) { return; }
  String_list_node *p = head_, *pp = 0;
  //int i = 0;
  while (p != 0) {
    pp = p;
    p = p->next_;
    // // DEBUG
    // cout << "(" << i++ << ") Deleting..." << endl;
    delete pp;
  }
}

void String_list::push_back(const string& s)
{
  if (head_ == 0) {
    assert(tail_ == 0);
    head_ = new String_list_node(s);
    tail_ = new String_list_node(string("dummy"));
    head_->next_ = tail_;
    tail_->prev_ = head_;
    ++size_;
    return;
  }
  assert(tail_ != 0);
  String_list_node *new_node = new String_list_node(s);
  String_list_node *p = tail_->prev_;
  p->next_ = new_node;
  new_node->prev_ = p;
  new_node->next_ = tail_;
  tail_->prev_ = new_node;
  ++size_;
}

Exercise 10-6

#include <iostream>
#include <string>

#include <gtest/gtest.h>

#include "String_list.hh"

using namespace std;

static String_list split(const string& s)
{
  String_list ret;

  string::const_iterator iter = s.begin();
  while (iter != s.end()) {
    while (iter != s.end() && isspace(*iter)) {
      ++iter;
    }
    if (iter == s.end()) { break; }
    string::const_iterator beg = iter;
    while (iter != s.end() && !isspace(*iter)) {
      ++iter;
    }
    ret.push_back(string(beg, iter));
  }

  return ret;
}

TEST(String_list, split)
{
  String_list sl = split(string("a b c d e f"));
  EXPECT_EQ(6, sl.size());
  String_list::iterator iter = sl.begin();
  EXPECT_STREQ("a", iter->c_str());
  EXPECT_STREQ("b", (++iter)->c_str());
  EXPECT_STREQ("c", (++iter)->c_str());
  EXPECT_STREQ("d", (++iter)->c_str());
  EXPECT_STREQ("e", (++iter)->c_str());
  EXPECT_STREQ("f", (++iter)->c_str());
}

int main(int argc, char **argv)
{
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}