【问题标题】:How to manage file unique IDs in c++如何在 C++ 中管理文件唯一 ID
【发布时间】:2015-10-03 02:59:39
【问题描述】:

c++(不是 c++11)

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

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

简而言之 - 我需要一种方法来为我的项目中的所有文件生成唯一 ID,我需要该文件能够在所有文件中使用相同的名称访问其自己的 ID,而且还能够访问另一个“管理器”文件中外部文件的 ID。

以下是不起作用的选项:

1。 枚举:

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

static thePrivateInstanceInThisFile = theFactory.makeInstance(fileID);

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

2。 计算自己的实例的类

在 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,该 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。

请提供一些好的方法来完成此操作

谢谢。

【问题讨论】:

  • 将其称为 C++03 或更旧的标准。 C++11 C++。
  • “我的项目中有 100 个 .cpp 文件”您可能应该使用数据库。我不明白您要做什么,但这几乎可以肯定是错误的方式。
  • 你能用__FILE__作为唯一ID吗?
  • FILE 接近,它在编译时生成一个唯一的 id。但是用户如何从“经理”访问文件?
  • @msw 回想起来,在项目失败后,这正是我失败的原因。应该使用数据库。我从中学到了。

标签: c++ uniqueidentifier


【解决方案1】:

这听起来像是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);

【讨论】:

  • 谢谢!您收到了我的问题,但我仍然缺少一件事:在您完成操作之后,我仍然需要一些可以按名称访问文件 ID 的外部“管理器”文件。在某些包含的 .h 文件中,类似于 file1.cpp int file1ID = getTheIdGiver().GetId();extern file1ID 中的内容。不过,是什么确保 file1ID 以正确的顺序实例化?
  • 我放弃了;我能想到的添加这个要求的唯一方法是如此复杂,最好在AllInstances 类中定义global.cpp 中的每个文件的实例,在global.h 中将其外部化,然后写在顶部每个文件都类似于“Instance &this_file_instance = AllInstances.file_59_instance”。
  • 请分享您考虑添加需求的方式,即使它很复杂。是什么以您的方式确保this_file_instance 在 file_59_instance 获得其 ID 之后获得其值?再次感谢
【解决方案2】:

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


ids.h

enum FileId
{
    File1, File2, File3
};

工厂.h

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

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

Factory &getTheFactory();

工厂.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();
}

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

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

然后在任何文件中,

  • 唯一 ID 由 FILEID 提供。 (对不起,这是一个宏)
  • 该文件的静态InstancegetThisFileInstance()获取。
  • 通过Manager&lt;any_file_id&gt;::getInstance()获取任意文件的静态Instance

这通过在每个文件中放置模板Manager&lt;FileId&gt; 的实例化实现来工作,每个文件都会创建并返回该文件的静态Instance

优点是 id 的持久性和零运行时开销:无需动态分配 id,对 Manager&lt;file_id&gt;::getInstance() 的调用在编译时解决。

此外,ids.h 标头可以通过脚本轻松生成,该脚本会扫描每个文件的第一行以查找 #define FILEID fileid,因此剩下的唯一维护就是记住写入 #define FILEID fileid

【讨论】:

  • 谢谢!这就像我想要的那样工作!现在我要做的就是让它适用于模板变量(不仅仅是实例),并在每个文件运行之前在本地 Insances 上调用 setter 方法。
  • 您好,我实现了这种唯一文件 ID 的方法,一切都如预期的那样完美。现在,出现了另一个要求 - 如果 2 个或更多文件需要具有相同的 ID 怎么办?或者更确切地说 - 2 个实例需要具有相同的 ID?由于 getInstance() 的双重定义,简单地通过 FILEID 提供相同的 ID 会失败。我正在考虑这里提出的一种方法codeproject.com/Articles/48575/… 但我很想听听任何更好的建议或一些指导再次感谢
  • 一个快速的解决方法是将getInstance 的定义用#ifndef DUPLICATE_ID 包围,然后在相关的cpp 文件中使用#define DUPLICATE_ID。然而,一种更为对称的做事方式是在global.cpp 或某处为每个ID 手动定义getInstance。但是与其他方法相比,您会失去自动化。
  • 也许我不明白你的意思。如果我这样做,那么仍然会多次定义该函数,因为在每个cpp文件中,第一次定义相关的FILEID,然后即使使用宏,该函数也会在多个文件中使用相同的签名定义保护。我没听懂吗?
  • 这个想法是,对于每个具有相同 id 的 cpp 文件,您将一个 DUPLICATE_ID 宏放在除一个之外的所有文件中,然后禁止除一个函数定义之外的所有文件。所以多个定义不是问题。
【解决方案3】:

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

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

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

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

所以我们的想法是在您的构建系统中生成UNIQUEID,并通过一些预处理器符号传递它。详细信息因操作系统、编译器、构建系统而异。

您还可以通过在构建过程中生成一些 C 或 C++ 源文件或头文件(可能使用一些 awk 脚本或一些 GPPm4 预处理)来做一些粗略的 meta-programming

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    相关资源
    最近更新 更多