我知道在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来实现更优化的实现吗?
答案 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();”确实