2

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. 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 ?

3
  • You could put the array in a class, initialize it in the constructor, and then use a static instance of that class. Commented Oct 24, 2013 at 19:50
  • Not really different than what you provided, but make the flag static as well (so you don't have that global variable). But why aren't you using a class? Commented Oct 24, 2013 at 19:51
  • I want a pretty optimal code to compile a password generetor from given characters and of given length. I thought that code will be simple enough that there is no use of a class Commented Oct 24, 2013 at 19:57

4 Answers 4

3

Ditch the pointer and use vector

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

The benefit is that it cleans itself up (no more calling delete.) cha-ching!

Sign up to request clarification or add additional context in comments.

Comments

1

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. I.e.

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

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

By the definition of value initialization:

C++11 § 8.5,p7

To value-initialize an object of type T means:

  • 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);

  • 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.

  • if T is an array type, then each element is value-initialized;

  • 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

To zero-initialize an object or reference of type T means:

  • 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)

  • 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;

  • 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;

  • if T is an array type, each element is zero-initialized;

  • if T is a reference type, no initialization is performed.

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.

8 Comments

Well, I use Dev-C++ 5.4.1 with MinGW originally added to it, so I don't know if I can use C++11 compliant code.
@user1978386 You'll know soon enough. Just try it. I'd say for sure whether it does or not, but I don't know MinGW well enough to make that call.
@user1978386 you don't need C++11 for this to work. It works in C++03.
@juanchopanza true that. It works on VS2010, for example, which is definitely not 11-compliant, though they find it necessary to spam you with a warning telling you its using a newer feature of the language. Go figure. Every 11 compiler I use does it right, but you're absolutely right. it is an 03x feature.
it compiles fine, but I didn't try it yet. Application generates 6.83 GB text file, so I need time to try it. I'll try and answer
|
0

Create a static function called AllocAndInit and call it like this (inside the function allocate and init the array you allocated):

static int *cur_pos = AllocAndInit(pass_len);

the AllocAndInit method should look like this :

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

    return ret;
}

Comments

0

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.

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. 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;" does not, but "static int y = rand();" does.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.