Visual Studio 2017 C++ Static analyzer (or in ReSharper C++)
-
Is there a switch in Visual Studio C++ Static Analyzer to catch the uninitialized member i. Or if you are using ReSharper C++ which one of the gazillion inspection options I would need to check to catch this? Thanks.
class Test
{
public:
Test(int i) : m_i(i)
{
std::cout << m_i << std::endl;
};
int m_i;
};class MainTest
{
public:
MainTest() : m_Test(i) {}; // i is not initialized here...Test m\_Test; int i = 33; // if I put this line before the line above it will be corrected.
};
int main()
{
MainTest m;std::cout << "Hello World!\\n";
}
I'd rather be phishing!
-
Is there a switch in Visual Studio C++ Static Analyzer to catch the uninitialized member i. Or if you are using ReSharper C++ which one of the gazillion inspection options I would need to check to catch this? Thanks.
class Test
{
public:
Test(int i) : m_i(i)
{
std::cout << m_i << std::endl;
};
int m_i;
};class MainTest
{
public:
MainTest() : m_Test(i) {}; // i is not initialized here...Test m\_Test; int i = 33; // if I put this line before the line above it will be corrected.
};
int main()
{
MainTest m;std::cout << "Hello World!\\n";
}
I'd rather be phishing!
Can't help you there, I would have expected VS to issue a warning. :doh: That said, it shouldn't make a difference where you put the declaration (and initialization) of i, because section 12.6.2 of the C++ standard says the order of initialization is always: 1. virtual base classes 2. base classes 3. non-static members (4. the body of the constructor is executed) Therefore, i can never be initialized by the time the base constructor is called (and if it is, the compiler has an error). The only way I can think of to initialize i before the base class, is having a (potentially different) base class initialize it - either by moving the member variable into that base class, or with the help of CRTP
template
struct make_i_great_again {
make_i_great_again(T& t) { t.i = 33; }
};
class Test {
...
};
class MainTest : public make_i_great_again, Test
{
public:
MainTest() : make_i_great_again(*this), Test(i) {}
int i;
};Technically this is a hack, because by the time you pass
*this
to your base class,this
isn't properly constructed. But since you're not reading fromo it, it might actually work. P.S.: oh well, forget all of the above. Somehow I thought you were inheriting from Test .... Anyway, you could simply use a static const instead of using your member variable:class MainTest {
static const int I_INIT = 33;
public:
MainTest() : m_Test(I_INIT) {}
Test m_Test;
int i = I_INIT;
};GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
-
Is there a switch in Visual Studio C++ Static Analyzer to catch the uninitialized member i. Or if you are using ReSharper C++ which one of the gazillion inspection options I would need to check to catch this? Thanks.
class Test
{
public:
Test(int i) : m_i(i)
{
std::cout << m_i << std::endl;
};
int m_i;
};class MainTest
{
public:
MainTest() : m_Test(i) {}; // i is not initialized here...Test m\_Test; int i = 33; // if I put this line before the line above it will be corrected.
};
int main()
{
MainTest m;std::cout << "Hello World!\\n";
}
I'd rather be phishing!
Now that is pretty interesting. The following code
#include using namespace std;
class Foo
{
int a = b;
int b = 5;public:
void show(){ cout << "a " << a << ", b " << b << endl;}};
class Boo
{
int a;
int b;
public:
Boo(): a(b), b(5){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};class Goo
{
int a;
int b=5;
public:
Goo():a(b){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};int main()
{
Foo f;
f.show();
Boo b;
b.show();
Goo g;
g.show();
}compiled with
g++ -Wall
issues NO warning and produces the following output on my Linux box
a 0, b 5
a 0, b 5
a 32766, b 5The lesson I learnt (while waiting for more clever people to add insight) is "Timeo Danaos and C++ Default Initializers for class members".
-
Now that is pretty interesting. The following code
#include using namespace std;
class Foo
{
int a = b;
int b = 5;public:
void show(){ cout << "a " << a << ", b " << b << endl;}};
class Boo
{
int a;
int b;
public:
Boo(): a(b), b(5){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};class Goo
{
int a;
int b=5;
public:
Goo():a(b){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};int main()
{
Foo f;
f.show();
Boo b;
b.show();
Goo g;
g.show();
}compiled with
g++ -Wall
issues NO warning and produces the following output on my Linux box
a 0, b 5
a 0, b 5
a 32766, b 5The lesson I learnt (while waiting for more clever people to add insight) is "Timeo Danaos and C++ Default Initializers for class members".
I've tried online GDB because I don't trust VS to be 100% standards comform, and it does the same. (not sure how to set warning level though; but it's gcc, so I wouldn't expect a different result than you). Then I looked up order of initialization, and although there are pretty detailed descriptions on the order of initializations of the stuff mentioned in a constructor, I haven't found a hint on when a static initialization is taking place! Btw.: interesting choice of names! You forgot Loo, though ;-) P.S.: While online GDB also does not offer a warning, it does generate a different result when run: a 0, b 5 a 32764, b 5 a 0, b 5 I'm not sure what to make of this :confused: P.P.S.: link to onlinegdb: https://www.onlinegdb.com/online_c++_compiler[^]
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
-
Is there a switch in Visual Studio C++ Static Analyzer to catch the uninitialized member i. Or if you are using ReSharper C++ which one of the gazillion inspection options I would need to check to catch this? Thanks.
class Test
{
public:
Test(int i) : m_i(i)
{
std::cout << m_i << std::endl;
};
int m_i;
};class MainTest
{
public:
MainTest() : m_Test(i) {}; // i is not initialized here...Test m\_Test; int i = 33; // if I put this line before the line above it will be corrected.
};
int main()
{
MainTest m;std::cout << "Hello World!\\n";
}
I'd rather be phishing!
I've found a site that explains a lot of rules and restrictions regarding non-static member initialization, but it didn't seem to contain any info on the initialization order : Non-static data members - cppreference.com[^] IMHO, given all the implications with special cases and dependencies, I don't think it's worth the hassle using this feature, unless you have a very good reason to use it. Especially if you can't rely on the compiler to catch potentially incorrect usage!
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
-
Now that is pretty interesting. The following code
#include using namespace std;
class Foo
{
int a = b;
int b = 5;public:
void show(){ cout << "a " << a << ", b " << b << endl;}};
class Boo
{
int a;
int b;
public:
Boo(): a(b), b(5){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};class Goo
{
int a;
int b=5;
public:
Goo():a(b){}
void show(){ cout << "a " << a << ", b " << b << endl;}
};int main()
{
Foo f;
f.show();
Boo b;
b.show();
Goo g;
g.show();
}compiled with
g++ -Wall
issues NO warning and produces the following output on my Linux box
a 0, b 5
a 0, b 5
a 32766, b 5The lesson I learnt (while waiting for more clever people to add insight) is "Timeo Danaos and C++ Default Initializers for class members".
Ok, I'll add some more mystery. Here's my take:
#include
using namespace std;
class Loo
{
public:
static int x;
static int y;
static int z;
int a;
int b = ++y;
int c;
Loo() : a(++x), c(b+(++z)) {}
Loo(int i) : a(++b), b(++i), c(++b) {}
void show(){ cout << "a " << a << ", b " << b << ", c " << c << endl;}
static void show_(){ cout << "x " << x << ", y " << y << ", z " << z << endl;}
};
int Loo::x = 0;
int Loo::y = 0;
int Loo::z = 0;
int main()
{
Loo::show_();
Loo l;
l.show();
Loo::show_();
Loo l5(5);
l5.show();
Loo::show_();
return 0;
}And the output I get is:
x 0, y 0, z 0
a 1, b 1, c 2
x 1, y 1, z 1
a 1, b 7, c 7
x 1, y 1, z 1The first two lines are unspectactular: they show what can be expected from the code. The third line is also unsurprising. Importantly, it shows that the member initialization of b was invoked by the default constructor (y=1). The fourth line however is very odd: It starts with a=1. How? Let's take apart the commonly known rules on initilization order: the initializer list gets processed left to right for all virtual base classes, than all base classes, then all members. We only have members, so initialization order is a, then b, then c. Next, according to this site Non-static data members - cppreference.com[^] the non-static member initialization of b gets skipped, because b is on the initalizer list. This means, b is not initialized at all by the time a is getting initialized! Note that y remains unchanged, proving that the member initializer is not invoked! Therefore the value assigned to a is undefined. As it seems, in this case b assumes a value of 0, incremented to 1, and then assigned to a. Next, b gets initialized. It's value is based on i, which is 5, so the value of b should be 6. The output shows 7 - but let's look further: we still have to initialize c, which again is based b, incrementing it. There