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

时间:2013-10-24 19:46:46

标签: c++ static initialization

我知道在C ++函数中使用'static'修饰符声明的变量只初始化一次,我想要做的是初始化具有适当内容的静态动态分配数组。这是我的代码片段:

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 ;
    ...
}

我当然知道我可以这样做:

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

但它可能不是最佳的编码方式,可以更有效地完成。我可以用某种方式使用'static'moddifier来实现更优化的实现吗?

4 个答案:

答案 0 :(得分:3)

抛弃指针并使用vector

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

好处是它可以清理自己(不再打电话给delete。)cha-ching!

答案 1 :(得分:1)

如果你想要它预先填充零(并且看起来你这样做),我能想到的最小变化是使用符合C ++ 11的工具链对该数组进行值初始化。即

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

关于它的工作原理,如果按照我的描述完成,则突出显示适用于初始分配如何用零填充的部分。

  

C ++11§8.5,p10

     

一个对象,其初始化程序是一组空的括号,即(),应为值初始化

通过值初始化的定义:

  

C ++11§8.5,第7页

     

对T类型的对象进行值初始化意味着:

     
      
  • 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T,初始化是错误的)没有可访问的默认构造函数);

  •   
  • 如果T是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,那么该对象是零初始化的,如果T的隐式声明的默认构造函数是非平凡的,那么构造函数被调用。

  •   
  • 如果T是数组类型,那么每个元素都是值初始化的;

  •   
  • 否则,该对象零初始化。

  •   

这使我们了解对象类型零初始化意味着什么:

  

C ++11§8.5,p5

     

零初始化T类型的对象或引用意味着:

     
      
  • 如果T是标量类型(3.9),则将对象设置为值0(零),作为整数常量表达式,转换为T (103)

  •   
  • 如果T是(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化**并且填充初始化为零位;

  •   
  • 如果T是(可能是cv限定的)联合类型,则对象的第一个非静态命名数据成员将进行零初始化,并将填充初始化为零位;

  •   
  • 如果T是数组类型,则每个元素都是零初始化的;

  •   
  • 如果T是引用类型,则不执行初始化。

  •   
     

103)如4.10中所述,将值为0的整型常量表达式转换为指针类型会导致空指针值。

答案 2 :(得分:0)

创建一个名为AllocAndInit的静态函数并像这样调用它(在函数allocate和init中分配你的数组):

static int *cur_pos = AllocAndInit(pass_len);

AllocAndInit方法应如下所示:

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

    return ret;
}

答案 3 :(得分:0)

带有构造函数的全局变量(和函数局部静态)在许多情况下可能会导致许多意外问题。随着程序规模和复杂程度的增长,这些事情可能会变得非常难以管理。

如果你明确地管理它们会更好 - 因为那样你就可以明确控制构造/破坏的顺序以及何时发生这些事情。

如果您使用上面建议的矢量,那么当程序退出时,矢量将被释放。但是,你不能直接控制发生这种情况的顺序,所以如果调用getNextPass()作为正在清理的其他东西的一部分(所以,在main()返回之后),它可能会崩溃,你将不得不拼图了解为什么以及如何使订购正确。

另请注意,函数本地静态初始化通常不是线程安全的。 GCC具有线程安全的初始化机制,但其他编译器(如VC)则没有。即使支持它也不是免费的,可能需要启用选项。

手动完成(非常类似于编译器自动生成的代码):

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;
    }
    ...

}

澄清一点“with constructors”意味着需要执行代码的初始化。 所以,“static int x = 5;”不,但“static int y = rand();”确实