简体   繁体   English

如何在C ++中对静态动态分配的数组进行静态初始化?

[英]How to make static initialization of a static dynamically allocated array in C++?

I know that variable which is declared with 'static' modifier in a C++ function is initialized only once and what I want to do is to initialize static dynamically allocated array with appropriate content. 我知道在C ++函数中用'static'修饰符声明的变量仅初始化一次,而我想做的是初始化具有适当内容的静态动态分配数组。 Here is my code fragment: 这是我的代码片段:

inline char* getNextPass()
{
    static int chars_num = chars_data.charset_len, pass_len = chars_data.pass_len ;
    static int *cur_pos = new int[pass_len] ;  // this is static variable in function, what means it's initialized only once

    ...
    for(int aa = 0; aa < pass_len; aa++)  // this is executed every time the function is called. How can I make this code execute only once ?
    cur_pos[aa] = 0 ;
    ...
}

I know of course that I could do something like this: 我当然知道我可以做这样的事情:

...
flag = true ;
...
inline char* getNextPass()
{
    ...
    if(flag)
    for(int aa = 0; aa < pass_len; aa++)
    cur_pos[aa] = 0 ;
    flag = false ;
    ...
}

but it's probably not optimal way of coding and can be done somehow more effectively. 但这可能不是最佳的编码方式,而且可以通过某种方式更有效地完成。 Can I use 'static' moddifier some way to make more optimized implementation ? 我可以通过某种方式使用“静态”修饰符来进行更优化的实现吗?

Ditch the pointer and use vector 抛开指针并使用vector

static vector<int> cur_pos(pass_len, 0);

The benefit is that it cleans itself up (no more calling delete .) cha-ching! 好处是它可以清理自身(不再调用delete )。

If you want it prefilled with zeros (and it appears you do), the most-minimal change I can think of is to value-initialize that array with a C++11 compliant toolchain. 如果您希望它用零预填充(看起来确实如此),那么我能想到的最微小的变化就是使用兼容C ++ 11的工具链对该数组进行值初始化。 Ie

static int *cur_pos = new int[pass_len](); // note the tail-parens.

Regarding why it works, highlighted portions applicable to how your initial allocation is filled with zeros if done as I describe. 关于它为什么起作用,突出显示的部分适用于您的初始分配,如果按照我的描述进行,则用零填充。

C++11 § 8.5,p10 C ++ 11§8.5,p10

An object whose initializer is an empty set of parentheses, ie, () , shall be value-initialized . 一个其初始值设定项是一个空括号集合(即())的对象 ,应进行值初始化

By the definition of value initialization : 通过值初始化的定义:

C++11 § 8.5,p7 C ++ 11§8.5,p7

To value-initialize an object of type T means: 值初始化类型T的对象意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor); 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化格式不正确) ;

  • if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T's implicitly-declared default constructor is non-trivial, that constructor is called. 如果T是(可能具有cv资格的)非工会类类型,而没有用户提供的构造函数,则该对象将初始化为零,并且,如果T隐式声明的默认构造函数非平凡,则将调用该构造函数。

  • if T is an array type, then each element is value-initialized; 如果T是数组类型,则每个元素都将值初始化;

  • otherwise, the object is zero-initialized. 否则,将对象初始化为零。

Which brings us to what it means for your object-type to be zero-initialized : 这使我们了解对您的对象类型进行零初始化的含义:

C++11 § 8.5,p5 C ++ 11§8.5,p5

To zero-initialize an object or reference of type T means: 零初始化类型T的对象或引用意味着:

  • if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T (103) 如果T是标量类型(3.9),则将对象设置为值0(零),作为整数常量表达式,转换为T (103)

  • if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized** and padding is initialized to zero bits; 如果T是(可能是cv限定的)非联合类类型,则将每个非静态数据成员和每个基类子对象初始化为零,并将填充初始化为零位;

  • if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero- initialized and padding is initialized to zero bits; 如果T是(可能是cv限定的)联合类型,则将对象的第一个非静态命名数据成员初始化为零,并将填充初始化为零位;

  • if T is an array type, each element is zero-initialized; 如果T是数组类型,则每个元素都初始化为零。

  • if T is a reference type, no initialization is performed. 如果T是引用类型,则不执行初始化。

103) As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer value. 103)如4.10中所述,将值为0的整数常量表达式转换为指针类型会导致指针值为空。

Create a static function called AllocAndInit and call it like this (inside the function allocate and init the array you allocated): 创建一个名为AllocAndInit的静态函数,并按如下方式调用它(在函数allocate中并初始化分配的数组):

static int *cur_pos = AllocAndInit(pass_len);

the AllocAndInit method should look like this : AllocAndInit方法应如下所示:

int * AllocAndInit(pass_len)
{
    int * ret = new int[pass_len];
    for (int i = 0 ; i < pass_len; ++i)
    // init here ....

    return ret;
}

Global variables (and function local statics) with constructors can cause a lot of unexpected problems in many situations. 构造函数的全局变量(和函数局部静态变量)在许多情况下会导致很多意外问题。 As programs grow in size and complexity these things can get to be very hard to manage. 随着程序的规模和复杂性的增长,这些事情将变得非常难以管理。

You will be better off if you manage them explicitly - because then you get explicit control over the order of construction/destruction and when these things happen. 如果您对它们进行显式管理,将会更好。因为这样您就可以对构建/破坏的顺序以及发生这些事情的时间进行显式控制。

If you use a vector as suggested above, then as the program exits the vector will be freed. 如果您按照上面的建议使用向量,那么在程序退出时,向量将被释放。 But, you cannot directly control the order in which this happens, so if getNextPass() is called as part of something else which is being cleaned up (so, after main() returns), it will likely crash and you will have to puzzle out why and how to get the ordering correct. 但是,您无法直接控制这种情况发生的顺序,因此,如果将getNextPass()作为正在清理的其他内容的一部分进行调用(因此,在main()返回之后),则可能会崩溃,并且您必须困惑指出为什么以及如何正确订购。

Also note that function local static initialization is not thread-safe in general. 还要注意,函数本地静态初始化通常不是线程安全的。 GCC has a thread-safe initialization mechanism, but other compilers (like VC) do not. GCC具有线程安全的初始化机制,但其他编译器(如VC)则没有。 Even when supported it isn't free and may require an option to enable. 即使受支持,它也不是免费的,并且可能需要启用某个选项。

Doing it manually (very similar to the auto-generated code by the compiler): 手动执行(非常类似于编译器自动生成的代码):

inline char* getNextPass()
{
    static bool initialized;
    static int chars_num;
    static int pass_len;
    static int *cur_pos;
    if (!initialized) {
        chars_num = chars_data.charset_len;
        pass_len = chars_data.pass_len ;
        cur_pos = new int[pass_len];    

        for(int aa = 0; aa < pass_len; aa++)  
            cur_pos[aa] = 0 ;
        initialized = true;
    }
    ...

}

To clarify a bit "with constructors" means an initialization which requires code to execute to do. 为了澄清“使用构造函数”,这意味着需要执行代码才能进行的初始化。 So, "static int x = 5;" 因此,“ static int x = 5;” does not, but "static int y = rand();" 不会,但是“ static int y = rand();” does. 确实。

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

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