问题
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:
Automatically created file IDs
Unique file IDs (which are very very preferably numbers)
Usage of those IDs by the same variable name in all files (automatically, using a static variable definition in the globals.h file)
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 Instance
s 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 bygetThisFileInstance()
. - The static
Instance
of any file is obtained byManager<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