객체의 유니크 아이디 생성하기

shi510의 이미지

문제의 코드

어떠한 객체를 인스턴스화 하였을 때 아이디의 유니크함을 보장해야하는 코드가 필요한데요.
Object obj1, obj2;
Print(obj1.Id());
Print(obj2.Id());

해결법 1

객체 내의 특정 자료형을 동적할당을 하여 해당 Memory Address를 유니크 아이디로 사용함.
객체가 메모리에서 제거되었을 때 같은 Memory Address가 할당될 가능성이 있음.
유니크함이 컴파일러 또는 시스템 의존적임.
class Object{
public:
    Object(){
        ptr_id = new int(0);
    }
    string Id(){
        return to_string((int)ptr_id));
    }
    ~Object(){
        delete ptr_id;
    }
private:
    int *ptr_id;
};

해결법 2

static unsigned int 자료형을 선언하여 객체가 할당될 때마다 ID를 선형 증가하도록함.
제 지식으로는 향후 문제의 여지가 있는 코드인지 모르겠습니다.
class Object{
public:
    Object(){
        id = _next_gen;
        _next_gen += 1;
    }
    string Id(){
        return to_string(id);
    }
private:
    int id;
    static unsigned int _next_gen;
};
unsigned int Object::_next_gen = 0;

방법2가 향후 문제가 없을까요?
아니면 다른 좋은 방법이 있을까요?

익명 사용자의 이미지

해결법 2가 대체로 좋은 방법입니다만, 주의할 점이 좀 있겠군요.

1. Object 객체가 복사(copy)되거나 대입(assign)될 때 id도 똑같이 덮어씌워지지 않도록 주의해야 합니다.
(그런 면에서 볼 때, id만 따로 별도의 클래스로 만드는 게 편리할 것 같군요.)

2. 멀티스레드 환경에서 사용중이면, 혹은 멀티스레드 환경에서 사용될 가능성이 있으면
_next_gen에서 발생할 수 있는 data race를 막을 방법을 준비해야 합니다. lock을 두는 편이 제일 간단하지요.

shi510의 이미지

객체가 서로 다른 thread에서 생성되는 경우는 생각을 못했네요.
thread safety는 좀 더 생각해야 겠습니다.
고맙습니다~

jick의 이미지

사실 1번 방법을 쓴다면 별도로 int를 할당할 필요도 없고 그냥 객체 자체의 주소를 사용하면 됩니다. (물론 객체를 복사하면 주소가 바뀐다는 문제가 있습니다만... 유니크 아이디가 필요한 상황에선 복사 자체가 필요없는 경우도 많기 때문에...)

익명이에요의 이미지

시간으로는 안 되나요?
생성 시간을 기록하면 유일할 것 같아요.
cpu 사이클이 빨라서 동일 시간에 여러개 생성될 수도 있겠군요
2번 해결책이 일반적이고 보통 id++ 로 합니다.
atomic 연산해야 합니다. thread-safe

익명이에요의 이미지

id = 0;
...
id = next_id++;

atomic 연산해야 되요.

twinwings의 이미지

Object 객체는 unique Id를 가지기만 하면 되지, 자기 자신이 생성할 필요가 없습니다.

만약 클러스터링 되는 환경, Server-Client 모델에서는 유니크 아이디를 어떻게 생성해야할까요?

따라서, 가장 일반적인 경우는 애초에 unique Id를 생성해주는 객체를 별도로 두는 설계입니다.

이럴 경우,
1) 단순하게 1씩 증가는 경우
2) DB와 연동하여 DB의 key을 객체의ID로 쓰는 경우
3) 클라이언트에서 서버에게 요청하여 Id값을 받은 후 할당하는 경우

모든 경우에 대해 유연하게 대처 할 수 있습니다.

즉, ID를 생성하는 객체만 교체가 된다면 기존의 Object 객체는 수정 없이 재활용 가능합니다.

// 해당 코드 블럭 이외에서 정의되어 있음.
// 어떻게 Id생성과 객체 생성 로직은 별개임.
ObjectIdGenterator *defaultGenerator;
 
Object *obj = new Object(deafultGenerator.nextId());

jick의 이미지

음.. 관점의 문제지만, 저보고 하라면 "객체 안에 다 집어넣고, 클러스터링 되는 환경이 필요해지면 그때 refactoring합시다"라고 하겠습니다.

소프트웨어 프로젝트를 말아먹는 흔한 패턴 중의 하나가 "혹시라도 사용자가 백만명을 넘어가서 서버가 수백 대 필요해지면 어쩌구 저쩌구..."해서 그걸 다 감안해서 그 상황에서 돌아갈 수 있는 프로그램을 짜다 보면 소스는 몇십만 줄이 넘어가고... 나중에 출시 시기를 놓쳐서 폭망... 뭐 그런 경우들이 있죠.

(물론 반대로 백만명이 정말로 써야 하는데 서버 한 대에 우겨넣고 "제가 혼자 써보니까 잘 돌던데요?" 하면 그것도 문제겠습니다만...)

twinwings의 이미지

본문에 설명을 생략했더니 이렇게 되었군요.

unique id generator를 인터페이스를 정의하고 그 구현체는 3가지 모두 구현 가능합니다. 이럴경우 모듈이 완벽하게 분리 되기때문에 다른 부분 수정없이 컴파일 및 링크가 되는 유연성있는 설계라고 말하고 싶었습니다. 단순하게 id 증분으로 코드 짜놓으면 10줄이면 되겠고, 인터페이스를 분리하였기에 추후에 리펙토링 필요하면 다른 모든 모듈에 영향을 끼치지 않겠지요.

결국 id생성자를 분리하는데 필요한 코드는 추기적으로 20줄 내외이고 언제 있을지 모르는 리펙토링에 조차 안전한 코드가 되는 겁니다.

c++ pimple idiom이 가장 간단한 얘가 되겠구요.
자바라면 interface로 정의했겠죠.
관련된 design pattern은 bridge pattern이 되겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.