Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

posted at

updated at

[小ネタ]C++で簡単なID生成器を作った

はじめに

ゲームとか作ってると雑にIDを割り振りたくなる場面があったりしますよね。
(なんかオブジェ生成するたびにIdをインクリメントして設定したりしてました)

ただ、雑にインクリメントするだけだと、使い終わったIdを再利用したりできず、インクリメントしつづけていつかオーバーフローするんじゃないかといった恐怖があったので、

使用しなくなったIDを再利用もできるような、簡単なID生成器を作りました。


追記
コメントいただいたのですが、そもそも64bit整数で管理する分には非現実レベルに長時間動かし続けない限りオーバフローすることはなさそうでした。
ようやくオーバフローした頃には、既に自分も墓の中にいるので大丈夫そうですね!

実装

いたってシンプルです。

IdGenerator.hpp
#include <cstdint>
#include <queue>
#include <limits>
#include <exception>

/// <summary>
/// Id生成器
/// </summary>
class IdGenerator
{
public:
    using value_type = std::int64_t;
public:
    /// <summary>
    /// Idの生成
    /// </summary>
    /// <returns></returns>
    value_type createId()
    {
        if (!m_freeIds.empty()) {
            auto id = m_freeIds.front();
            m_freeIds.pop();
            return id;
        }
        if (m_nextId == std::numeric_limits<value_type>::max()) [[unlikely]] {
            throw std::runtime_error("can't be generated Id by max limit.");

            // Fail Safeでもよい
        }
        return m_nextId++;
    }        

    /// <summary>
    /// Idの開放
    /// </summary>
    /// <param name="id"></param>
    void releaseId(value_type id)
    {
        m_freeIds.push(id);
    }        

    /// <summary>
    /// リセット
    /// </summary>
    void reset()
    {
        m_nextId = 0;

        // queue clear
        std::queue<value_type> empty;
        m_freeIds.swap(empty);
    }        
private:
    value_type m_nextId = 0;
    std::queue<value_type> m_freeIds;
};

基本はインクリメントしていく、使い終わったIDはreleaseIdメソッドに渡すことで
キューにため込んでおき、キューが空じゃない時はそこからポップしてIdを返すようにしています。

⚠️未生成なIdをリリースしたらバグりますが、いちいちvalidationするのもコストなのでその辺はやってないです。

使い方

    IdGenerator idGen;

    // ID生成
    auto id_0 = idGen.createId(); // 0

    // ID生成
    auto id_1 = idGen.createId(); // 1

    // ID 0 使い終わった
    idGen.releaseId(id_0);

    // ID生成 再利用される
    auto new_id_0 = idGen.createId(); // 0

    // ID生成
    auto id_2 = idGen.createId(); // 2

まとめ

今回は小ネタでしたが、簡単に使えるID生成器を紹介しました。
使い終わったIDを再利用してオーバーフローしないように安心感を得ましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?