How to manage file unique IDs in c++

99封情书 提交于 2020-03-06 03:51:22

问题


c++ (not c++11)

Say i have 100 .cpp files in my project, which currently do some work. All of those files currently include some globals.h file which i can edit easily.

I want each of those files to have its own instance of some object, and I also want that instance to have some unique ID of the file in which it is instantiated. In addition, I want those objects to be created by a factory method, and I need the instances to have some way for a user to handle them - meaning they can't be anonymous.

In short - I need a way to generate unique IDs for all of the files in my project, i need the file to be able to access its own ID using the same name in all files, but also to be able to access the ID of a file externally in another "manager" file.

Here are options that don't work:

1. Enum:

If I use an enum and give every file an enum ID, now I can't do this in globals.h:

static thePrivateInstanceInThisFile = theFactory.makeInstance(fileID);

because I need a different fileID in every file, and that was defined statically, and uniquely named using my enum.

2. Class that counts its own instances

Define in 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());

This will give an ID to each static file instace which is unique to the file, but now it is not manageable externally to the file.

I thought about doing something like

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

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

file1.cpp
file1ID = theFileId.getFileID();

file2.cpp
file2ID = theFileId.getFileID();

...

and whenever a user needs to manage a file he would either use the file's ID variable, or create a new one in the above manner.

This would allow me to access each uniquely and automatically file ID externally. The only problem I have with this is the line file1ID = theFileId.getFileID(); only executes in runtime, AFTER the line static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID());. which executes at compile time.

I can't figure out a good way to reverse this order, or maybe do a whole other mechanic.

Again - I need:

  1. Automatically created file IDs

  2. Unique file IDs (which are very very preferably numbers)

  3. Usage of those IDs by the same variable name in all files (automatically, using a static variable definition in the globals.h file)

  4. Ability to access a specific file ID manually by using another manually defined variable.

Please advise some good way to accomplish this

Thanks.


回答1:


If you want to be able to access the static Instances of other files, then this cannot be done via an automatically generated id because the id generated for a file could change each time a new file is added, or every time it is compiled, or even on each execution. Therefore in this solution, each file manually defines its own persistent id similarly to example 1 in the question.


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

Usage is as follows: for each file requiring a static Instance object, place at the start

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

Then in any file,

  • The unique id is given by FILEID. (sorry it's a macro)
  • The static Instance of this file is obtained by getThisFileInstance().
  • The static Instance of any file is obtained by Manager<any_file_id>::getInstance().

This works by placing the implementation for an instantiation of the template Manager<FileId> in each file, each of which creates and returns that file's static Instance.

Advantages are persistence of ids, and zero run-time overhead: no need to dynamically assign ids, and the calls to Manager<file_id>::getInstance() are resolved at compile-time.

Also, the ids.h header can easily be generated by a script which scans the first line of each file for #define FILEID fileid, so the only maintenance left is remembering to write #define FILEID fileid.




回答2:


This sounds like a bad case of the static initialization order fiasco.

Here is a solution which uniquely assigns integer ids to each file, then generates a unique Instance by calling a factory function with the file's id, while ensuring that the Instance factory is initialized before its first use:

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);



回答3:


You might modify your building procedure (e.g. your Makefile) to define some unique thing. E.g. you could compile your foo23.cpp file with something like (assuming GCC on some Linux system; adapt this to your compiler and OS and builder)

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

You could get the 23 for UNIQUEID using some shell script or whatever, e.g. an ad-hoc rule in your Makefile. Details depend upon your file naming conventions.

then use appropriately BASENAME and UNIQUEID in your C or C++ code (perhaps with dirty #if UNIQUEID==23 preprocessor tricks...).

So the idea is to generate the UNIQUEID in your build system and to pass it thru some preprocessor symbols. Details are OS, compiler, build-system specific.

You might also do some crude meta-programming by generating some C or C++ source or header file (perhaps using some awk script or some GPP or m4 preprocessing) in your building procedure.



来源:https://stackoverflow.com/questions/31407210/how-to-manage-file-unique-ids-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!