FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

C++11のスマートポインタを導入

Effective Modern C++を読んでいたら、スマートポインタというのを見つけた。正直、何者なのか知らなかったので調査してみると、 メモリリークなどの誤動作を防ぐためのポインタ機構らしい。 例えば、スマートポインタを使うとdeleteが不要になったり、例外を考慮する必要が無くなる。

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

そこで、試しにスマートポインタの勉強のために、ISSの一部にスマートポインタを導入してみた。

github.com

CMakeを使って、C++11をビルドできるようにする

gccC++11のオプションが利用できるように、以下をCMakeLists.txtに加えた。

add_definitions("-std=c++0x")

usagi.hatenablog.jp

スマートポインタを使って、ISSのメモリを確保する。

ISSでは、メモリアクセスを発生させる前にメモリを探索し、既にその領域が確保されていればそのまま参照、そうでなければ領域を新規作成する。 このルーチンをスマートポインタで置き換えてみる。

MemResult Memory::InsertMemTable (Addr_t addr, Word_t data)
{
    // at first, traverse memory table and check memory region is already registered or not

    std::map<Addr_t, std::unique_ptr<MemoryBlock>>::iterator it;
    Addr_t baseaddr = addr & 0xFFFFF000ULL;
    if ((it = m_memory_vec.find (baseaddr)) != m_memory_vec.end()) {
        it->second->WriteByte (addr - baseaddr, static_cast<Byte_t>(data));
        return MemNoExcept;
    }

    std::unique_ptr<MemoryBlock> memory_block (new MemoryBlock (baseaddr, 0x1000ULL, 0x7));

    memory_block->WriteByte (addr - baseaddr, static_cast<Byte_t>(data));
    m_memory_vec.insert (std::make_pair(baseaddr, std::move(memory_block)));

    return MemNewRegion;
}

まずはイテレータを作成し、マップの中を、当該アドレスの領域が存在するかを探索している。 スマートポインタに対するマップは同様に作成することができ、探索にはfindを使っている。

次に、メモリアドレスが存在しない場合は、まずはstd::unique_ptrのスマートポインタを作成し、新しくMemoryBlockクラスをインスタンスする。 マップに挿入するときは、make_pairでペアを生成するのだが、その際にポインタの権限を移譲するために、std::moveを使ってstd::mapに挿入している。

これ、その前のWriteByteのメソッドが存在しなければ、

    m_memory_vec.insert (std::make_pair(baseaddr, std::unique_ptr<MemoryBlock> (new MemoryBlock (baseaddr, 0x1000ULL, 0x7)));

でも良いみたいなのだが、一度作成したインスタンスで処理を行う必要があるため、今回はstd::moveを使っている。