如何在 C++ 中管理文件唯一 ID

How to manage file unique IDs in c++

c++(不是 c++11)

假设我的项目中有 100 个 .cpp 文件,它们目前正在做一些工作。 所有这些文件目前都包含一些我可以轻松编辑的 globals.h 文件。

我希望这些文件中的每一个都有自己的某个对象实例,并且我还希望该实例具有实例化它的文件的一些唯一 ID。 此外,我希望通过工厂方法创建这些对象,并且我需要实例为用户提供某种方式来处理它们——这意味着它们不能是匿名的。

简而言之——我需要一种方法来为我项目中的所有文件生成唯一的 ID,我需要文件能够在所有文件中使用相同的名称访问它自己的 ID,而且能够在另一个 "manager" 文件中访问外部文件的 ID。

以下选项无效:

1。 枚举:

如果我使用枚举并为每个文件指定一个枚举 ID,现在我无法在 globals.h 中执行此操作:

static thePrivateInstanceInThisFile = theFactory.makeInstance(fileID);

因为我需要在每个文件中使用不同的 fileID,并且它是静态定义的,并使用我的枚举唯一命名。

2。 Class 计算自己的实例

在globals.h中定义:

class FileIDGiver{
private:
   static int currentID;//initialize to 0 in cpp
   int myID;
public:
   FileIDGiver(){
      myID = currentID++;
   }
   int getFileID(){
       return myID;
   }
}

static FileIDGiver theFileId;

static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID());

这将为每个静态文件实例提供一个文件唯一的 ID,但现在无法在文件外部对其进行管理。

我考虑过做类似的事情

globals.cpp
int file1ID;
int file2ID;
...

globals.h
extern file1ID;
extern file2ID;
...

file1.cpp
file1ID = theFileId.getFileID();

file2.cpp
file2ID = theFileId.getFileID();

...

每当用户需要管理文件时,他要么使用文件的 ID 变量,要么以上述方式创建一个新文件。

这将允许我从外部访问每个唯一且自动的文件 ID。 我遇到的唯一问题是行 file1ID = theFileId.getFileID(); 仅在运行时在行 static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID()); 之后执行。 在编译时执行。

我想不出一个好方法来颠倒这个顺序,或者做一个完整的其他机制。

再次 - 我需要:

  1. 自动创建的文件 ID

  2. 唯一文件 ID(最好是数字)

  3. 所有文件中相同变量名对这些 ID 的使用(自动,使用 globals.h 文件中的静态变量定义)

  4. 能够使用另一个手动定义的变量手动访问特定文件 ID。

请指教一些完成此任务的好方法

谢谢。

这听起来像是 static initialization order fiasco 的糟糕案例。

这是一个解决方案,它为每个文件唯一分配整数 ID,然后通过使用文件 ID 调用工厂函数生成唯一的 Instance,同时确保 Instance 工厂在之前初始化它的第一次使用:

idgiver.h:

class IdGiver
{
    int id;
public:
    IdGiver() : id(0) {}
    int getId() {return id++;}
};

IdGiver &getTheIdGiver();

idgiver.cpp:

#include "idgiver.h"

IdGiver &getTheIdGiver()
{
    static IdGiver theIdGiver;
    return theIdGiver;
}

factory.h:

class Instance
{
    // ...
};

class Factory
{
    // ...
public:
    Factory() : {/*...*/}
    Instance getInstance(int id) {/*...*/}
};

Factory &getTheFactory();

factory.cpp:

#include "factory.h"

Factory &getTheFactory()
{
    static Factory theFactory;
    return theFactory;
}

globals.h:

#include "idgiver.h"
#include "factory.h"

static int      thisFileId       = getTheIdGiver().getId();
static Instance thisFileInstance = getTheFactory().getInstance(thisFileId);

您可以修改您的构建程序(例如您的 Makefile)来定义一些独特的东西。例如。你可以用类似的东西编译你的 foo23.cpp 文件(假设 GCC 在一些 Linux 系统上;适应你的编译器和 OS 和构建器)

  g++ -Wall -c -DBASENAME="$(basename foo23.cpp)" -DUNIQUEID=23

您可以使用一些 shell 脚本或其他任何东西为 UNIQUEID 获得 23,例如Makefile 中的临时规则。详细信息取决于您的文件命名约定。

然后在您的 C 或 C++ 代码中适当地使用 BASENAMEUNIQUEID(可能使用肮脏的 #if UNIQUEID==23 预处理器技巧...)。

所以我的想法是 在您的构建系统中生成 UNIQUEID 通过一些预处理器符号 传递它。详细信息是 OS、编译器、构建系统特定的。

您也可以在构建过程中进行一些粗略的 meta-programming by generating some C or C++ source or header file (perhaps using some awk script or some GPP or m4 预处理。

如果您希望能够访问其他文件的静态 Instances,那么这不能通过自动生成的 ID 来完成,因为每次新文件生成时,为文件生成的 ID 可能会更改添加,或者每次编译时,甚至每次执行时。因此,在这个解决方案中,每个文件都手动定义了自己的持久标识,类似于问题中的示例 1。


ids.h

enum FileId
{
    File1, File2, File3
};

factory.h

#include "ids.h"
#include "instance.h"

class Factory
{
    // ...
public:
    Factory() {/*...*/}
    Instance createInstance(FileId fileid) {/*...*/}
};

Factory &getTheFactory();

factory.cpp

#include "factory.h"

Factory &getTheFactory()
{
    static Factory theFactory;
    return theFactory;
}

idmanager.h

#include "ids.h"
#include "instance.h"

template<FileId id>
struct Manager
{
    static Instance &getInstance(); // not defined
};

global.h

#include "idmanager.h"
#include "factory.h"

template <>
Instance &Manager<FILEID>::getInstance()
{
    static Instance theInstance = getTheFactory().getInstance(FILEID);
    return theInstance;
};

static Instance &getThisFileInstance()
{
    return Manager<FILEID>::getInstance();
}

用法如下:对于每个需要静态Instanceobject的文件,放在开头

#define FILEID File1   // The FileId corresponding to this file
#include "global.h"

然后在任何文件中,

  • 唯一 ID 由 FILEID 给出。 (抱歉这是一个宏)
  • 这个文件的静态Instance是通过getThisFileInstance()获得的。
  • 任何文件的静态Instance通过Manager<any_file_id>::getInstance()获取。

这是通过在每个文件中放置模板 Manager<FileId> 实例化的实现来实现的,每个文件都会创建 returns 该文件的静态 Instance.

优点是 ID 持久化和零 run-time 开销:不需要动态分配 ID,对 Manager<file_id>::getInstance() 的调用在 compile-time 解析。

此外,ids.h header 可以很容易地通过扫描每个文件第一行的脚本生成 #define FILEID fileid,所以唯一剩下的维护就是记住写 #define FILEID fileid.