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
Using Opengl Glutdisplayfunc Within Class
Bytewise Reading of Memory: "Signed Char *" VS "Unsigned Char *"
Using Pair as Key in a Map (C++/Stl)
Win32 Setforegroundwindow Unreliable
Sfinae and Partial Class Template Specializations
Search 25 000 Words Within a Text
Creating a String List and an Enum List from a C++ MACro
Creating a Lock That Preserves the Order of Locking Attempts in C++11
How to Convert a String of Hex Values to a String
C++ Trying to Get Function Address from a Std::Function
In C/C++ Why Does the Do While(Expression); Need a Semi Colon
Brute-Force, Single-Threaded Prime Factorization
Compile Time String Encryption Using Constexpr
Is There Any G++ Option to Dump Class Layout and Vtables
Instantiate Class with or Without Parentheses