2015-01-20 66 views
1

我确信之前已经询问过这个问题,但问题的术语很混乱,而且我足够新C++的顶部我甚至不确定我正确使用它,所以我一直无法找到它以前问。如果我错过了,请原谅我。将所有类实例的列表存储在类中作为静态数组

(如果有人就足以纠正我的问题语法专家请这样做,这样我可能会在未来更精确的;-))

我需要定义一个类,其中一个成员数组存储指向该类的所有实例的指针。该数组由每个成员都有的整数id索引。

因此到接入:

MyClass testcase = MyClass(); 
int i = testcase.id; 
MyClass* tempVar; 
tempVar = MyClass::InstanceRecord[i]; // this is the procedure in ? 

应该填充的TempVar的指针该类的测试用例'的新创建的实例。通过这种方式,班级成员可以通过他们的'身份证'成员互相引用。

我的问题来声明数组'InstanceRecord'。我无法控制数组的填充顺序(换句话说就是创建了类的实例),并且id编号是预定义的[段落编辑]。因此,我需要使用形式:(注意:这是在类定义内)

static MyClass* InstanceRecord[MAXIMUM_POSSIBLE_INSTANCES] = {x}; 

为了声明数组,并填充所述阵列的整个宽度在一个步骤中。这样我可以在调用MyClass()(构造函数)期间更改数组中给定元素的值。

问题是我不知道如何用不存在的内存指针填充数组。请有人向我解释在前面的陈述中属于我的'='的权利,还是以另一种方式做到这一点?

编辑:类定义是这样的:

class MyClass{ 
    Public: 
    MyClass(string fileName){ 

     // Initialize class members from file data 
     // including the id member 

     // list of other members which require a status of True 
     // before this item has an available of True. id1-id5 
     // represent id members of other instances of this class. 
     // these id's all come from hard files. 
     required_data[] = {id1, id2, id3, id4,id5}; 
     available=0; //boolean false 
     status=0; //boolean false 

     // is this the right way to do a vector of pointers? 
     InstanceRecord[id]= this; 
    } 

    MyClass* get_instance_by_id(int i){ 
     return InstanceRecord[i]; 
    } 

    bool is_available(){ 
     return available; 
    } 

    void update_available(){ 
     int sum = 0; 
     for (int i = 0; i<5 ;i++){ 
     if (InstanceRecord[required_data[i]].status == 1 || required_data[i] == 0){ 
      sum +=1; 
     } 
     } 
     if (sum >=5){ 
     available = 1; 
     } 
    } 

    Private: 
    int id; 
    std::vector<MyClass*>InstanceRecord (MAX_INSTANCES, nullptr); 
    int required_data[5]; 
    bool status; 
    bool available; 
} 

EDIT:将样品数据文件(评论通常不允许的,但增加了清晰度)

Widget Glue Removal Tool // becomes MyClass.name 
1251      // becomes MyClass.id 
...lots of other stuff... // becomes MyClass.[some_var_name] 
14,37,1841,15,27   // becomes the id1...id5 which must be 
          // status checked to determine this 
          // object's available flag. These ints 
          // are the id's (like this 1251) of those 
          // other instances. 

该数据实际上为宠物这是一个电子游戏我的项目。该课程代表“研究树”中的一个项目,在新课题可用前必须先完成必要的研究。树和主题不一定是线性的。在获得对项目47的访问权限之前,您可能必须研究项目20,400,12和15(因此,ID为20,400,12和15的实例都必须具有状态= 1,表明它们在项目47可用之前已完成= 1显示在研究项目选择窗口中)。由于研究树是通过读取目录中的每个文件进行填充的,因此以非受控序列填充,所以当创建类的第一个实例时,我需要用某种空指针(假设为nullptr)填充我的索引向量。我最初的问题是,并且实质上仍然是如何用这些数据填充矢量。我现在知道

std::vector<MyClass*>InstanceRecord(MAX_POSSIBLE_INSTANCES, X); 

应该满足我的需求,但可以nullptr替换这行中的X?

Barry的答案中的Factory类实际上教会了我很多,但下一个答案似乎更符合我的需求。在这一点上,我只是试图确定是否Michaels的答案可以简单地修改为:

id=<data read in from file>; 
InstanceRecord[id]=this; 

在他的答案的第五和第六行。如我所说,我只是C++中的一员,显然我对术语缺乏正确的理解,因此无法很好地陈述问题,这导致了一些混淆。编译时间来测试这将是巨大的,所以我希望在我开始这个过程之前尽可能地获得几乎没有bug的东西(不是我们全部)。

+0

原始指针在现代C++中被认为是不好的做法,您可能需要查看[shared_ptr](http://en.cppreference.com/w/cpp/memory/shared_ptr)。考虑到InstanceRecord的可扩展性,使用[vector](http://www.cplusplus.com/reference/vector/vector/)可能是有意义的。 – foips 2015-01-20 22:00:58

+0

如果你只是想跟踪每个班级的实例,我相信下面@Barry的答案会有效。 – 2015-01-20 22:23:58

+0

它可能在那,但我已经足够新的C++,我不得不逐一逐行地看这个答案,以了解它...... ;-) – Jase 2015-01-21 00:32:15

回答

1

您可以通过添加跟踪向量作为静态实例做到这一点。 您还需要从销毁时的跟踪向量中移除该项目。如果您从多个线程创建/更新,则需要适当地锁定/解锁它。

它可能看起来有点像这样没有锁定。

class MyClass{ 
    Public: 
    MyClass(string fileName){ 
     status=0; 
     id = instanceRecord.size(); 
     instanceRecord.push_back(this);   
    } 

    ~MyClass() { 
     //Clear it so that we dont access invalid data in update_available. 
     instanceRecord[id]=NULL; 
    } 

    static MyClass* get_instance_by_id(int i){ 
     //TODO: Add bounds checking here. 
     return instanceRecord.get(i); 
    }  

    void update_available(){ 
     int sum = 0; 
     for (int i = 0; i<5 ;i++){ 
     MyClass * instance = instanceRecord[i]; 
     if(instance==NULL) 
      continue; 
     if (instanceRecord[required_data[i]].status == 1 || required_data[i] == 0){ 
      sum +=1; 
     } 
     } 
     if (sum >=5){ 
     available = 1; 
     } 
    } 

    private: 
    int id; 
    static std::vector<MyClass*>instanceRecord; 
    ... 
} 

然后,您需要添加一个.cpp文件中添加静态载体 - 这样的事情。

std::vector<MyClass> MyClass::instanceRecord = std::vector<MyClass>(); 

如果你需要锁定,那么你就需要添加一个静态锁定对象,封装所有访问instanceRecord与锁。

最后一个限制条件是,如果您在主外部创建MyClass的任何实例,则可能会遇到由于使用静态变量而导致的"static initialization order fiasco"。有些方法可以使用某些单例方法,但它们使事情看起来更加复杂,所以在简单情况下不值得。

+0

这看起来更像我以后,我唯一的问题是'id'的任务。我编辑了这个问题来添加一个示例数据文件(类似于用于实例化类的一个对象),并带有注释来解释字段的用法。你能否回顾一下并告诉我这将如何修改你的建议? – Jase 2015-01-21 04:16:50

+0

如果您不是使用'id'作为顺序计数器,而是需要将其作为输入,则需要从'std :: vector '中的跟踪切换到'std :: map '。您可能还需要检查id的唯一性 - 您也可以使用该地图。 – 2015-01-21 05:19:10

2

我想你想要的是一个对象工厂:

template <typename T> 
class Factory { 
private: 
    static std::vector<std::unique_ptr<T>> instances; 

public: 
    static T* create() { 
     std::unique_ptr<T> obj{new T}; 
     obj->id = instances.size(); 
     instances.emplace_back(std::move(obj)); 
     return instances.back().get(); 
    } 

    static T* get(size_t idx) const { 
     return instances[idx].get(); 
    } 
}; 

的情况下使用,如:

MyClass* testcase = Factory<MyClass>::create(); 
assert(testcase->id == 0); 
assert(Factory<MyClass>::get(0) == testcase); 
+0

所以如果我理解这个权利...我仍然定义MyClass(像上面但没有“跟踪元素”),并通过类Factory(用于创建类Factory的MyClass的类实例)和MyClass的新实例然后使用Factory :: get(x)查找MyClass的实例X;哪个返回指针? – Jase 2015-01-21 00:52:00

+0

@Jase非常。尽管'MyClass'仍然需要'id'。 – Barry 2015-01-21 00:53:42

+0

这个工厂类看起来很有趣,但如果我正确地阅读它(工厂),则会根据创建顺序分配一个ID。请看看我编辑的问题(我刷新了一些例子)。 update_available函数是我需要这些以某种方式工作的全部原因。有没有一种方法可以用工厂类来做到这一点? – Jase 2015-01-21 02:15:33

相关问题