简体   繁体   English

动态分配数组的静态指针

[英]Static Pointer to Dynamically allocated array

So the question is relatively straight forward, I have several semi-large lookup tables ~500kb a piece. 所以问题相对简单,我有几个半大的查找表~500kb一块。 Now these exact same tables are used by several class instantiations (maybe lots), with this in mind I don't want to store the same tables in each class. 现在这些完全相同的表被几个类实例化(可能很多)使用,考虑到这一点,我不想在每个类中存储相同的表。 So I can either dump the entire tables onto the stack as 'static' members, or I can have 'static' pointers to these tables. 所以我可以将整个表作为“静态”成员转储到堆栈中,或者我可以对这些表有“静态”指针。 In either case the constructor for the class will check whether they are initialized and do so if not. 在任何一种情况下,类的构造函数都将检查它们是否已初始化,如果不是,则执行此操作。 However, my question is, if I choose the static pointers to the tables (so as not to abuse the stack space) what is a good method for appropriately cleaning these up. 但是,我的问题是,如果我选择表的静态指针(以免滥用堆栈空间)什么是适当清理这些的好方法。

Also note that I have considered using boost::share_ptr, but opted not to, this is a very small project and I am not looking to add any dependencies. 另请注意,我考虑过使用boost :: share_ptr,但选择不使用,这是一个非常小的项目,我不打算添加任何依赖项。

Thanks 谢谢

Static members will never be allocated on the stack. 静态成员永远不会在堆栈上分配。 When you declare them (which of course, you do explicitly), they're assigned space somewhere (a data segment?). 当你声明它们时(当然,你明确地做了),它们被分配了空间(数据段?)。

If it makes sense that the lookup tables are members of the class, then make them static members! 如果查找表是类的成员是有意义的,那么让它们成为静态成员!

When a class is instanced on the stack, the static member variables don't form part of the stack cost. 当一个类在堆栈上实例化时,静态成员变量不构成堆栈成本的一部分。

If, for instance, you want: 例如,如果您想要:

class MyClass {
    ...
    static int LookUpTable[LARGENUM];
};

int MyClass:LookUpTable[LARGENUM];

When you instance MyClass on the stack, MyClass:LookUpTable points to the object that you've explicitly allocated on the last line of the codesample above. 当您在堆栈上实例MyClass时,MyClass:LookUpTable指向您在上面的代码示例的最后一行显式分配的对象。 Best of all, there's no need to deallocate it, since it's essentially a global variable; 最重要的是,没有必要解除分配,因为它本质上是一个全局变量; it can't leak, since it's not on the heap. 它不会泄漏,因为它不在堆上。

If you don't free the memory for the tables at all, then when your program exits the OS will automatically throw away all memory allocated by your application. 如果你根本没有释放表的内存,那么当你的程序退出时,操作系统会自动丢弃你的应用程序分配的所有内存。 This is an appropriate strategy for handling memory that is allocated only once by your application. 这是处理仅由应用程序分配一次的内存的适当策略。

Leaving the memory alone can actually improve performance too, because you won't waste time on shutdown trying to explicitly free everything and therefore possibly force a page in for all the memory you allocated. 单独保留内存实际上也可以提高性能,因为您不会浪费时间在关闭时尝试显式释放所有内容,因此可能强制页面进入您分配的所有内存。 Just let the OS do it when you exit. 退出时,让操作系统执行此操作。

If these are lookup tables , the easiest solution is just to use std::vector: 如果这些是查找 ,最简单的解决方案就是使用std :: vector:

class SomeClass {
  /* ... */
  static std::vector<element_type> static_data;
};

To initialize, you can do: 要初始化,您可以执行以下操作:

static_data.resize(numberOfElements);
// now initialize the contents

With this you can still do array-like access, as in: 有了这个,你仍然可以进行类似数组的访问,如:

SomeClass::static_data[42].foo();

And with any decent compiler, this should be as fast as a pointer to a native array. 对于任何体面的编译器,这应该与指向本机数组的指针一样快。

Why don't you create a singleton class that manages the lookup tables? 为什么不创建管理查找表的单例类? As it seems they need to be accessed by a number of classes; 因为它们似乎需要被许多类访问; make the singleton the manager of the lookup tables accessible at global scope. 使单例可以在全局范围内访问查找表的管理器。 Then all the classes can use the singleton getters/setters to manipulate the lookup tables. 然后所有类都可以使用单例getter / setter来操作查找表。 There are 3 advantages to this approach:- 这种方法有3个优点: -

  • If the static container size for the lookup tables becomes large then the default stack-size may ( 1MB on Windows) lead to stack-overflow on application statrt-up itself. 如果查找表的静态容器大小变大,那么默认的堆栈大小(Windows上为1MB)会导致应用程序statrt-up本身的堆栈溢出。 Use a container that allocates dynamically. 使用动态分配的容器。

  • If you plan to access the table via multiple-threads, the singleton class can be extended to accompany locked access. 如果您计划通过多线程访问该表,则可以扩展单例类以配合锁定访问。

  • You can also cleanup in the dtor of singleton during application exit. 您还可以在应用程序退出期间在单例的dtor中进行清理。

I can think of several ways to approach for this depending upon what is trying to be accomplished. 根据想要完成的工作,我可以想到几种方法来解决这个问题。

If the data is static and fixed, using a static array which is global and initialized within the code would be a good approach. 如果数据是静态的并且是固定的,那么使用全局的静态数组并在代码中初始化将是一种很好的方法。 Everything is contained in the code and loaded when the program is started so it is available. 一切都包含在代码中,并在程序启动时加载,因此可用。 Then all of the class which need access can access the information. 然后,所有需要访问的类都可以访问该信息。

If the data is not static and needs to read in, an static STL structure, such as a vector, list or map would be good as it can grow as you add elements to the list. 如果数据不是静态的并且需要读入,则静态STL结构(例如矢量,列表或映射)会很好,因为它可以在向列表中添加元素时增长。 Some of these class provides lookup methods as well. 其中一些类也提供了查找方法。 Depending upon the data you are looking up, you may have to provide a structure and some operator to have the STL structures work correctly. 根据您正在查找的数据,您可能必须提供一个结构和一些运算符,以使STL结构正常工作。

In either of the two case, you might what to make a static global class to read and contain the data. 在这两种情况中的任何一种情况下,您可能想要创建一个静态全局类来读取和包含数据。 It can take care of managing initialization and access the data. 它可以负责管理初始化和访问数据。 You can use private members to indicate if the class has been read in and is available for use. 您可以使用私有成员来指示该类是否已被读入并可供使用。 If it has not, the class might be able to do the initialization by itself if it has enough information. 如果没有,如果有足够的信息,该类可以自己进行初始化。 The other class can call static function of the static global class to access the data. 另一个类可以调用静态全局类的静态函数来访问数据。 This provides encapsulation of the data, and then it can be used by several different classes without those classes needing to incorperate the large lookup table. 这提供了数据的封装,然后它可以被几个不同的类使用,而这些类不需要包含大型查找表。

There are several possibilties with various advantages and disadvantages. 有几种可能的优点和缺点。 I don't know what the table contains, so I'll call it an Entry . 我不知道该表包含什么,所以我将其称为Entry

If you just want the memory to be sure to go away when the program exits, use a global auto_ptr: 如果您只想在程序退出时确保内存消失,请使用全局auto_ptr:

auto_ptr<Entry> pTable;

You can initialize it whenever you like, and it will automatically be deleted when the program exits. 您可以随时初始化它,并在程序退出时自动删除它。 Unfortunately, it will pollute the global namespace. 不幸的是,它会污染全局命名空间。

It sounds like you are using the same table within multiple instances of the same class . 听起来您在同一个类的多个实例中使用相同的表。 In this case, it is usual to make it a static pointer of that class: 在这种情况下,通常使它成为该类的静态指针:

class MyClass {
...
protected:
   static auto_ptr<Entry> pTable;
};

If you want it to be accessible in instances of different classes , then you might make it a static member of a function, these will also be deleted when the program exits, but the really nice thing is that it won't be initialized until the function is entered. 如果你希望它可以在不同类的实例中访问,那么你可以使它成为函数的静态成员,这些也将在程序退出时被删除,但真正好的是它不会被初始化,直到输入功能。 Ie, the resource won't need to be allocated if the function is never called upon: 即,如果从未调用该函数,则不需要分配资源:

Entry* getTable() {
    static auto_ptr<Entry> pTable = new Entry[ gNumEntries ];
    return pTable;
}

You can do any of these with std::vector<Entry> rather than auto_ptr<Entry> , if you prefer, but the main advantage of that is that it can more easily be dynamically resized. 如果您愿意,可以使用std::vector<Entry>而不是auto_ptr<Entry>执行任何操作,但主要优点是可以更轻松地动态调整大小。 That might not be something you value. 这可能不是你重视的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM