2015-07-14 3 views
0

C++ (не C++ 11)Как управлять уникальными идентификаторами файлов в C++

Скажем, у меня есть 100 файлов .cpp в моем проекте, которые в настоящее время выполняют некоторую работу. Все эти файлы в настоящее время содержат файл globals.h, который я могу легко редактировать.

Я хочу, чтобы каждый из этих файлов имел свой экземпляр какого-либо объекта, и я также хочу, чтобы этот экземпляр имел уникальный идентификатор файла, в котором он был создан. Кроме того, я хочу, чтобы эти объекты были созданы с помощью фабричного метода, и мне нужны экземпляры, чтобы иметь какой-то способ для пользователя обрабатывать их, то есть они не могут быть анонимными.

Вкратце - мне нужен способ генерации уникальных идентификаторов для всех файлов в моем проекте, мне нужен файл, чтобы иметь возможность доступа к его собственному идентификатору с использованием одного и того же имени во всех файлах, а также для возможности доступ к ID файла извне в другом файле «manager».

Вот варианты, которые не работают:

1. Enum:

Если я использовать перечисление и дать каждый файл в перечислимом ID, теперь я не могу сделать это в глобал .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()); 

Это даст идентификатор каждого статического instace файла, который является уникальным для файла, но теперь он внешне не управляется файлом.

Я думал о делать что-то вроде

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

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

file1.cpp 
file1ID = theFileId.getFileID(); 

file2.cpp 
file2ID = theFileId.getFileID(); 

... 

и всякий раз, когда пользователь должен управлять файл, он будет либо использовать переменную идентификационного файла или создать новый в описанном выше порядке.

Это позволит мне получить доступ к каждому уникальному и автоматически идентификатору файла извне. Единственная проблема, с которой я столкнулся, это линия file1ID = theFileId.getFileID(); выполняется только во время выполнения, ПОСЛЕ линии static thePrivateInstanceInThisFile = theFactory.makeInstance(theFileId.getFileID());. , который выполняется во время компиляции.

Я не могу найти хороший способ отменить этот заказ, или, может быть, сделать целый другой механик.

Опять же - мне нужно:

  1. Автоматически создаваемые идентификаторы файлов

  2. Уникальные идентификаторы файлов (которые очень очень предпочтительно числа)

  3. Использование этих идентификаторов одним и тем же именем переменной во всех файлах (автоматически, используя определение статической переменной в глобалях.h файл)

  4. Возможность доступа к конкретному идентификатору файла вручную с использованием другой вручную определенной переменной.

Пожалуйста посоветуйте хороший способ сделать это

Спасибо.

+0

Назовите его C++ 03 или более старым стандартом. C++ 11 * - * C++. – Bathsheba

+1

«У меня есть 100 файлов .cpp в моем проекте», вероятно, вы должны использовать базу данных. Я не понимаю, что вы пытаетесь сделать, но это почти наверняка неправильный путь. – msw

+0

Не могли бы вы использовать '__FILE__' как уникальный идентификатор? – PBS

ответ

1

Если вы хотите иметь доступ к статическим Instance другим файлам, то это невозможно сделать с помощью автоматически генерируемого идентификатора, поскольку идентификатор, сгенерированный для файла, может меняться каждый раз при добавлении нового файла или каждый раз он компилируется или даже выполняется при каждом выполнении. Поэтому в этом решении каждый файл вручную определяет свой собственный постоянный идентификатор аналогично примеру 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(); 
} 

Использование выглядит следующим образом: для каждого файла, требующего статического Instance объекта, место на старте

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

Тогда в любой файл,

  • Уникальный идентификатор задается FILEID. (извините, что это макрос)
  • Статический Instance этого файла получен getThisFileInstance().
  • Статический Instance любого файла получен Manager<any_file_id>::getInstance().

Это работает, помещая реализацию для конкретизации шаблона Manager<FileId> в каждом файле, каждый из которых создает и возвращает этот файл статику Instance.

Преимуществами являются постоянство идентификаторов и нулевые служебные данные: нет необходимости динамически назначать идентификаторы, а вызовы Manager<file_id>::getInstance() разрешаются во время компиляции.

Кроме того, заголовок ids.h может быть сгенерирован сценарием, который сканирует первую строку каждого файла для #define FILEID fileid, поэтому единственное оставшееся обслуживание оставляет за собой право записать #define FILEID fileid.

+0

Спасибо! Это работает так, как я хотел! Теперь мне остается только заставить его работать с переменными шаблона (а не только с экземпляром) и вызывать методы setter на локальных Insances перед каждым файлом. – Gulzar

+0

Привет Я реализовал этот метод уникальных идентификаторов файлов, и все идеально, как ожидалось. Теперь возникает другое требование. Что делать, если у 2 или более файлов должен быть одинаковый идентификатор? вернее - 2 экземпляра должны иметь одинаковый идентификатор? Простое предоставление того же идентификатора через FILEID не удается из-за двойного определения getInstance(). Я рассматриваю один из способов, предложенных здесь http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-ah-file-and-imp , но я хотел бы услышать какие-нибудь лучшие предложения или какое-то руководство Еще раз спасибо – Gulzar

+0

Быстрое обходное решение kullge должно было бы объединить определение 'getInstance' с' #ifndef DUPLICATE_ID', а затем '#define DUPLICATE_ID' в соответствующих файлах cpp. Однако гораздо более симметричным способом делать вещи было бы вручную определить 'getInstance' для каждого идентификатора, в' global.cpp' или где-нибудь. Но тогда вы теряете автоматизацию по сравнению с другим методом. – PBS

2

Это звучит как плохой случай static initialization order fiasco.

Вот решение, которое однозначно присваивает целочисленные идентификаторы для каждого файла, а затем генерирует уникальный 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); 
+0

Спасибо! У меня есть вопрос, но я все еще пропущу одну вещь: После того, что вы сделали, мне по-прежнему нужен внешний файл «manager», который имеет доступ к идентификаторам файлов по имени. Что-то вроде в файле1.cpp 'int file1ID = getTheIdGiver(). GetId();' и 'extern file1ID' в некотором включенном файле .h. Тем не менее, что гарантирует, что файл1ID будет создан в правильном порядке? – Gulzar

+0

Я сдаюсь; единственный способ, который я могу придумать для добавления этого требования, настолько усложнен, что было бы лучше просто определить экземпляр каждого файла в 'global.cpp' в классе' AllInstances', externing это в 'global.h', а затем написать в верхней части каждого файла что-то вроде «Instance & this_file_instance = AllInstances.file_59_instance'. – PBS

+0

Просьба поделиться тем, как вы можете думать о добавлении требования, хотя это сложно. Что делает так, что 'this_file_instance' получает свое значение ПОСЛЕ того, как файл_59_instance получил свой ID? Еще раз спасибо – Gulzar

0

Вы можете модифицировать процедуру здания (например, ваш Makefile), чтобы определить какую-то уникальную вещь. Например. Вы можете компилировать foo23.cpp файл с чем-то вроде (предполагается, что GCC на некоторых системах Linux, адаптировать это к вашему компилятору и ОС и строитель)

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

Вы можете получить 23 для UNIQUEID с помощью какой-то скрипт или что-то, например правило ad hoc в вашем Makefile. Подробности зависят от ваших соглашений об именах файлов.

затем использовать надлежащим образом BASENAME и UNIQUEID в вашем C или C++ кода (возможно, с грязными #if UNIQUEID==23 препроцессора уловок ...).

Так что идея состоит в том, чтобы генерировать UNIQUEID в системе сборки и передать его через несколько символов препроцессора. Подробности - это ОС, компилятор, конкретная система сборки.

Вы можете также сделать некоторые сырой meta-programming генерируя некоторые C++ или источника или заголовка файла C (возможно, используя некоторые awk сценарий или некоторые GPP или m4 предварительной обработки) в вашей процедуре строительства.

 Смежные вопросы

  • Нет связанных вопросов^_^