【问题标题】:Auto generate ID in C++在 C++ 中自动生成 ID
【发布时间】:2012-04-24 20:38:34
【问题描述】:
// AnE.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;


// The maximum number of patients in queue
#define MAXPATIENTS 30


// define structure for patient information
struct patient

{
   char FirstName[50];
   char LastName[50];
   char ID[20];
};


// define class for queue
class queue
{
   public:
   queue (void);
   int RegisterPatien (patient p);
   int RegisterPatientAtBeginning (patient p);
   patient GetNextPatient (void);
   int CancelAll (patient * p);
   void OutputList (void);
   char DepartmentName[50];
   private:
   int ShowAllPatient;
   patient List[MAXPATIENTS];
};


// declare member functions for queue

queue::queue ()
{
   // Constructor
   ShowAllPatient = 0;
}


int queue::RegisterPatien (patient p)
{
   // To add a patient (normally) to the queue (to the end).
   // returns 1 if successful, 0 if queue is full.
  if (ShowAllPatient >= MAXPATIENTS)
   {
      // queue is full
      return 0;
   }
      // put in new patient
      else
      List[ShowAllPatient] = p;  ShowAllPatient++;
      return 1;
}


int queue::RegisterPatientAtBeginning (patient p)
{
   // adds a critically ill patient to the beginning of the queue.
   // returns 1 if successful, 0 if queue is full.
   int i;
   if (ShowAllPatient >= MAXPATIENTS)
   {
      // queue is full
      return 0;
   }

   // move all patients one position back in queue
   for (i = ShowAllPatient-1; i >= 0; i--)
   {
      List[i+1] = List[i];
   }
   // put in new patient
   List[0] = p;  ShowAllPatient++;
   return 1;
}


patient queue::GetNextPatient (void)
{
   // gets the patient that is first in the queue.
   // returns patient with no ID if queue is empty

   int i;  patient p;
   if (ShowAllPatient == 0) {
   // queue is empty
   strcpy(p.ID,"");
   return p;}
   // get first patient
   p = List[0];
   // move all remaining patients one position forward in queue
   ShowAllPatient--;
   for (i=0; i<ShowAllPatient; i++)
   {
      List[i] = List[i+1];
   }
   // return patient
   return p;
}


int queue::CancelAll (patient * p)

{
   // removes a patient from queue.
   // returns 1 if successful, 0 if patient not found
   int i, j, found = 0;
   // search for patient
   for (i=0; i<ShowAllPatient; i++)
    {
            if (stricmp(List[i].ID, p->ID) == 0)
        {
        // patient found in queue
        *p = List[i];  found = 1;
        // move all following patients one position forward in queue
        ShowAllPatient--;

    for (j=i; j<ShowAllPatient; j++)
                {
                        List[j] = List[j+1];
                }
        }
    }
   return found;
}


void queue::OutputList (void)
{
   // lists entire queue on screen
   int i;
   if (ShowAllPatient == 0)
    {
            cout<< "Queue is empty";
    }
   else
    {

        for (i=0; i<ShowAllPatient; i++)
        {
            cout << "First Name : " << List[i].FirstName<<endl;
            cout << "Last Name : " << List[i].LastName<<endl;
        }
    }
}


// declare functions used by main:

patient InputPatient (void)

{
   // this function asks user for patient data.
   patient p;
   cout<<endl<<endl;
   cout << "Please enter the information of the Patient"<<endl<<endl;
   cout << "First name: "<<endl<<endl;
   cin.getline(p.FirstName, sizeof(p.FirstName));
   cout << "Last name: "<<endl<<endl;
   cin.getline(p.LastName, sizeof(p.LastName));
   // check if data valid
   if (p.FirstName[0]==0 || p.LastName[0]==0 || p.ID[0]==0)
    {
            // rejected
            strcpy(p.ID,"");
            cout << "Error: Data not valid. Operation cancelled.";
            getch();
    }
   return p;
}


void OutputPatient (patient * p)
{
   // this function outputs patient data to the screen
   if (p == NULL || p->ID[0]==0)
    {
            cout << "No patient";

    return;
    }
   else
   cout << "Patient Information:"<<endl<<endl;
   cout << "First name: " << p->FirstName<<endl<<endl;
   cout << "Last name: " << p->LastName<<endl<<endl;
}


int ReadNumber()
{
   // this function reads an integer number from the keyboard.
   // it is used because input with cin >> doesn't work properly!
   char buffer[20];
   cin.getline(buffer, sizeof(buffer));
   return atoi(buffer);
}


void DepartmentMenu (queue * q)
{
   // this function defines the user interface with menu for one department
   int choice = 0, success;  patient p;
   while (choice != 6)
    {
        // print menu
           system("CLS");
           cout << "<< || Welcome || >> "<<endl << q->DepartmentName<<endl;
           cout << "Please enter your choice:"<<endl<<endl;
           cout << "1:  Register patient"<<endl;
           cout << "2:  Serve patient "<<endl;
           cout << "3:  Cancel all patients from queue"<<endl;
           cout << "4:  Show all patient"<<endl;
           cout << "5:  Exit"<<endl<<endl<<endl<<endl<<endl<<endl<<endl<<endl;

           choice = ReadNumber();

        switch (choice)
      {
            case 1:   // Add new patient
        p = InputPatient();
        if (p.ID[0])
           {
                success = q->RegisterPatien(p);
                system("CLS");
                if (success)
                {
                    cout << "Patient added:"<<endl<<endl;

                }
            else
           {
                // error
                cout << "Sorry: The queue is full. We Cannot add any patient:";
           }
                OutputPatient(&p);
                cout << "Press any key";
                getch();
      }
     break;

      case 2:   // Call patient for operation /First Come First Surve
     p = q->GetNextPatient();
     system("CLS");
     if (p.ID[0])
        {
           cout << "Patient to operate:";
           OutputPatient(&p);
     }
     else
        {
           cout << "Currently there is no patient to operate.";
     }
           cout << "Press any key to contiune";
           getch();
           break;

      case 3:   // Cancel all from queue
     p = InputPatient();
     if (p.ID[0])
       {
            success = q->CancelAll(&p);
            system("CLS");          
            if (success)
              {
                cout << "Patient removed:";
              }
              else
              {
                // error
                cout << "Sort: We cannot find patient:";
              }
        OutputPatient(&p);
            cout << "Press any key to contiune";
            getch();
       }
     break;

      case 4:   // Show all patient -> queues
          system("CLS");
          q->OutputList();
     cout << "Press any key";
     getch();  break;
     }
      }
}


// the main function defining queues and main menu
void main ()
{
   int i, MenuChoice = 0;
   // define  queue
   queue department[1];
   // set department name
   strcpy_s (department[0].DepartmentName, "To Emergency Department");

   while (MenuChoice != 2)
    {
        system("CLS");

// Cout menu
           cout<<"\n------------------------------------\n";
           cout << "Welcome to Waiting Room Management System"<<endl;
           cout<<"---------------------------------------\n";
           cout << "Please Select a Number from the following menu:"<<endl<<endl;
          for (i = 0; i < 1; i++)

    {
           // write menu item for department i
           cout<< "" << (i+1) << ":  "<< department[i].DepartmentName;
           cout<<endl;
          }
          cout << "2:  Exit"<<endl;
          // get user choice
          MenuChoice = ReadNumber();
          // is it a department name?
            if (MenuChoice >= 1 && MenuChoice <= 1)
            {
            // call submenu for department
            // (using pointer arithmetics here:)
            DepartmentMenu (department + (MenuChoice-1));
            }
    }
}

好的,候诊室是 Vc++。您可以看到代码运行良好,但生成 ID 有问题!我需要为每个患者生成 ID(由系统自动生成)。如何为我的队列生成 ID? 非常感谢!

【问题讨论】:

  • 您为什么使用char[20] 作为您的患者 ID?为什么不int 或者,如果有这么多患者,long
  • 它曾经是任何患者的社交 ID!那我就改变主意了!
  • 我强烈地感觉到这是一项学校作业。我们应该帮助人们解决他们的学校作业吗?
  • @dascandy,你不应该做任何事情。 ;-) 如果您愿意,您可以提供帮助。有些人帮助,有些人忽视,有些人辱骂。
  • 你好@sahpersian 欢迎来到 Stackoverflow。一般来说,您可能希望在问题的标题中更加具体,并且最好将代码放在问题之后,而不是之前。

标签: c++ auto-generate


【解决方案1】:

其他答案很好,但当前接受的答案实际上并不是另一位用户指出的线程安全的。

要生成线程安全的 ID 生成函数,我们可以使用原子!这是对当前接受的答案的修改,使其成为线程安全的。

#include <atomic> //std::atomic_uint32_t

class patient 
{ 
    // ...
    uint32_t id;

    static std::atomic_uint32_t current_id; // added

    patient() : id(current_id++) {} // added
};

uint32_t patient::current_id; // added

std::atomic_uint32_t 是一个 32 位无符号整数,如果由两个不同的线程同时写入,它(因为它是原子的)不会有任何数据竞争。

我还将整数更改为无符号。这是因为 ID 永远不会是负数,因此将其设为无符号是有意义的。

https://en.cppreference.com/w/cpp/atomic/atomic

【讨论】:

    【解决方案2】:

    我对 SQL 数据库也有同样的需求,最终得到了这个...

    警告:主要是混合 C 和 C++ 的不良编程示例(仍需要转换旧代码),但它是为了传达这个想法。我确信存在更好的解决方案...

    它(不幸的是)根据当前日期和时间生成基于大字符的 ID。这意味着每个下一个自动生成的 ID 都需要更大:如果它相等或更小,则附加一个毫秒计时器,代码将等待直到 ID 变得唯一。它也可以在没有毫秒的情况下工作,但是如果您需要一次生成多个 ID(每次暂停一秒钟),这将导致长时间的延迟。如果需要,它还会添加一个可选的后缀(可以帮助省略毫秒)。

    我对简单计数器的经验是,它们在某些情况下可能会重复,这让我寻找替代方案。

    小心:另一台计算机上的另一个用户可能会生成相同的 ID...(相同的秒或毫秒)

    TUID::TUID()
    
    {
     *LastID = 0; // char [80] - Global within object
    }    
    
    
    void TUID::GetToday (int *d, int *m, int *y)
    
    {
      time_t now;
      struct tm *ltm;
    
      time (&now);
      ltm = localtime (&now);
    
      *y = ltm->tm_year + 1900;
      *m = ltm->tm_mon + 1;
      *d = ltm->tm_mday;
    }
    
    
    void GetTime (int *h, int *m, int *s)
    
    {
    time_t t = time(0);   // get time now
    struct tm * now = localtime( & t );
    
    *h = now->tm_hour;
    *m = now->tm_min;
    *s = now->tm_sec;
    }
    
    
    const char *TUID::NewUID (bool bPreviousAttemptFailed, const char *_postfix)
    
    {
      int d, m, y,
          _h, _m, _s;
      bool bSameAsLastUID;
      char _uid [80];
    
      GetToday (&d, &m, &y);
    
      do
        {
          GetTime (&_h, &_m, &_s);
          sprintf (_uid, "%04d%02d%02d_%02d%02d%02d%s", y, m, d, _h, _m, _s, _postfix);
          bSameAsLastUID = (strcmp (_uid, LastUID) <= 0);
          if (bPreviousAttemptFailed || bSameAsLastUID)
            sprintf (_uid + strlen (_uid), "_%d", 
    std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());
        }
      while (strcmp (_uid, LastUID) <= 0);
    
      strcpy (LastUID, _uid);
    
      return LastUID;
    }
    

    这导致 ID 是这样的:

    20170816_115904 (no post-fix)
    20170816_115904i (with post-fix keeping id unique, preventing milliseconds)
    20170816_115904i_6427264 (auto-added milliseconds to keep ID unique)
    20170816_115904i_6427265
    20170816_115904i_6427266
    

    【讨论】:

      【解决方案3】:

      您可以在创建患者时使用静态变量(如果您需要它),该变量在构造函数中自增,或者您队列中的变量在您添加患者时增加(如果您只想分配排队时的 ID)。

      但在你的情况下,我认为你想要第一个解决方案(构造函数中的静态变量)。

      【讨论】:

      • 你可以参考Jerry Coffin的例子。
      【解决方案4】:

      通常,您可以通过在该类中放置一个static 变量来做到这一点,并且每次获得新患者时,将其当前值分配给当前患者,然后将其递增。

      class patient { 
          // ...
          int id;
      
          static int current_id; // added
      
          patient() : id(current_id++) {} // added
      };
      
      int patient::current_id; // added
      

      【讨论】:

      • 谢谢 Jerry 我能举个例子吗?因为我不知道!!非常感谢
      • 这不是线程安全的。您可能至少应该提到这一点。
      • @LuchianGrigore:考虑到所涉及的代码级别,我认为呈现有意义的必要解释更多的是混淆而不是澄清。
      • 真的很坦克老兄,我明白了概念....但我仍然对此感到困惑!它的生成ID,好吧,现在我想再次编写代码,代码也显示ID。你能帮我吗?我理解使用“静态”,但真的不知道如何使用它并展示它!
      • @sahpersian:一旦你创建了一个patient,他们的id 就像其他任何数据成员一样只是一个普通的数据成员,你可以像其他任何人一样显示它。
      【解决方案5】:

      如果您想要唯一的 ID,您可以生成一个 GUID。对于 VC++,你可以使用:

      extern C
      {
         #include <Rpc.h>
      }
      
      //...
      UUID id;
      UuidCreate ( &id );
      

      【讨论】:

      • 能否再举一个生成唯一 ID 的示例?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 2017-08-25
      • 2016-07-23
      • 2013-02-04
      • 2021-10-30
      • 1970-01-01
      相关资源
      最近更新 更多