Getting a Bunch of Crosses Initialization Error

Getting a bunch of crosses initialization error

The C++ standard says:

It is possible to transfer into a block, but not in a way that
bypasses declarations with initialization. A program that jumps from a
point where a local variable with automatic storage duration is not in
scope to a point where it is in scope is ill-formed unless the
variable has POD type (3.9) and is declared without an initializer.

The cases in switch are considered as a "jump".

Just put all objects and variables initializations before your switch, and everything will be fine.

Consider this code:

switch(k)
{
case 1:
int t = 4;
break;
default:
break;
}

It will cause a "crosses initialization" error, because it is possible to skip the initialization of t, but after that it will still be in scope, even though it was never created in the first place.

Now consider this:

switch(k)
{
case 1:
{
int t = 4;
}
break;
default:
break;
}

Here, you will not have the error, because the variable is inside a block, and will die at the end of the block ( at the closing { ), so after that it will not be in scope in any case.

To fix the first case, you just need to do:

int t = 0;
switch(k)
{
case 1:
t = 4;
break;
default:
break;
}

crosses initialization error in switch case statement

newB is in the scope of the switch statement, which makes it available in all switch cases, but won't be initialised in all of them. You should enclose each case in its own local scope (see this answer for more information):

switch (enumType) {
case enum1 :
{
B* newB = new B("foobar");
vectorOfAs.push_back(newB);
break;
}
case enum2 :
{
C* newC = new C("barfoo");
vectorOfAs.push_back(newB);
break;
}
}

At which point you will get a compiler error in enum2 (thereby exposing a bug), in that you are pushing newB not newC, which is what I assume you intended:

switch (enumType) {
case enum1 :
{
B* newB = new B("foobar");
vectorOfAs.push_back(newB);
break;
}
case enum2 :
{
C* newC = new C("barfoo");
vectorOfAs.push_back(newC); // <--
break;
}
}

This should work.

crosses initialization of variable only when initialization combined with declaration

Jumping past the initialization of an object, even if the object is of type int, is always undefined behavior. Note, that the switch-statement's statement isn't anything special: It is just a statement and people have [ab-]used this interesting ways, e.g., for Duff's Device. The only thing which is special within the statement is that labels can take the form default: and case <const-integer-expr>:.

The statement int i; is a definition of the variable but no initialization. Thus, no initialization of a variable is by-passed. There is no bigger problem jumping past this definition than there is in the first place. Of course, the value gets assigned when jumping to case 1: and not when jumping to case 2: but this is no different than what happens in code outside of switch-statements if people only define variables.

What are the signs of crosses initialization?

The version with int r = x + y; won't compile either.

The problem is that it is possible for r to come to scope without its initializer being executed. The code would compile fine if you removed the initializer completely (i.e. the line would read int r;).

The best thing you can do is to limit the scope of the variable. That way you'll satisfy both the compiler and the reader.

switch(i)
{
case 1:
{
int r = 1;
cout << r;
}
break;
case 2:
{
int r = x - y;
cout << r;
}
break;
};

The Standard says (6.7/3):

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer (8.5).

Crosses initialization of string and jump to label case

case labels are really a lot like dreaded goto labels; they do not constitute a new scope. Consequently, a switch selecting the correct case label to jump to is, for better or worse, a lot like goto statement jumping to a label. The jump is not allowed to cross the initialisation of your various objects - exactly as the error messages say.

The cleanest thing for you to do would be to cut everything between case 1: and break; case 2: and paste it into a new function called something like enterCar.

void enterCar() {
// code previously found between the case labels
}

// ...
switch(choice1) {
case 1: enterCar(); break;
case 2:
// ...
}

A function constitutes a new scope in which your local objects can be correctly initialised. As a bonus, you are making first steps towards leaving all the spaghetti code behind you.

C++ cross initiialization error

The compiler is correct: C++ does not allow you to skip over a variable declaration in the same scope. goto is similarly restricted.

If you need SaveLogin for all cases then declare it above the switch. If you only need it for case 2 then use scope blocks:

case 2 /*not directly relevant but there's no need for the parentheses*/:
{
// register
ofstream SaveLogin; /*ToDo - more logic here unless it's contained
fully within construction and destruction*/
break;
}
case 3:

jump to case label crosses initialization of 'std::unique_lock<std::mutex>'

switch(opn_type) {
case 1: {
std::unique_lock<std::mutex> ul(m);
// do processing and add to queue
cv.notify_one();
ul.unlock();

} break;

default:
break;
}

case labels don't end variable lifetime, so ul exists and is destroyed after default: but only initialized within case 1:.

Put it in a block.

switch(opn_type) {
case 1: {
std::unique_lock<std::mutex> ul(m);
// do processing and add to queue
cv.notify_one();
} break;

default:
break;
}

the .unlock() does nothing, as the scope is ending right there. In this version I removed it.

Note that I find mixing threading primitives with other code to be dangerous.

template<class T>
struct threadsafe_queue {
T pop() {
auto l = lock();
cv.wait(lk, [&]{return !queue.empty();});
T retval = queue.front();
queue.pop_front();
return retval;
}
void push( T in ) {
auto l = lock(m);
queue.push_back(std::move(in));
cv.notify_one();
}
std::deque<T> pop_all() {
auto l = lock();
return std::move(queue);
}
private:
mutable std::mutex m;
std::condition_variable cv;
std::deque<T> queue;
std::unique_lock<std::mutex> lock() const {
return std::unique_lock<std::mutex>(m);
}
};

adding "try_pop", "try_pop_for" etc is an exercise.



Related Topics



Leave a reply



Submit