Why is my static array[] of my classes failing - c++

I can certainly solve this half a dozen ways but I am curious why what I have coded is not working. (VS 2010 Pro C++)
I have a small class
class Protocol_element
{
public:
const char *Argument;
int EnumID;
int TrueEnum;
int FalseEnum;
bool IsEnabled;
...
It has an explicit ctor:
Protocol_element(const char * arg, int id, int tru, int fals, bool isEnab)
{
Argument = arg;
EnumID = id;
TrueEnum = tru;
FalseEnum = fals;
IsEnabled = isEnab;
{
Then I have an array of addresses of these class elements that is declared static
Protocol_element *Parms::Protocol[] = {
&Protocol_element("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true),
&Protocol_element("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true),
&Protocol_element("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true),
&Protocol_element("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false),
&Protocol_element("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false),
&Protocol_element("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false),
nullptr
};
I can trace with the debugger through the constructors. I can see my whole array get built just as I would expect. But if I breakpoint on int main() the array now is uninitialized storage.
Why? Why did my array "disappear"?

Okay, thanks. I was not sure, but when it compiled, I expected that it might work. As I said, I can think of a dozen ways to solve the problem, and what I have done now, and works, is
Protocol_element Parms::Protocol[] = {
{ "SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true },
{ "SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true },
{ "TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true }, // TODO: Document
{ "TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false },
{ "TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false },
{ "TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false },
nullptr
};

The program is invalid. The address-of operator requires an lvalue.
You are however using a non-standard language extension of a very buggy and outdated compiler. This extension prevents the compiler from yelling at you and refusing to compile the program like the standard (any year) requires. Unfortunately it does not cause the compiler to emit meaningful code. So garbage in, garbage out.
You should upgrade to the latest version of MSVC and use the latest standard (the /std:c++latest flag), or at the very least disable the non-standard extensions with the /Za flag. I cannot guarantee it will help specifically with VS 2010 though, but it does help with modern versions of MSVC.

Related

How to customize function parameter errors(c++)

I wrote a function that requires two parameters, but I don't want those two parameters to be 0.
I want to make the compiler know that those two parameters cannot be 0 through some ways, otherwise the editor will report an error in the form of "red wavy line".
I refer to "custom exception class" to solve this problem, but I find this method does not work.
If there are someone knows how to do , I will be very happy, because it takes me a whole day
For example:
#include<iostream>
using namespace std;
int Fuction(int i , int j){
//code
}
int main(){
Funciton(1,1);
Funciton(0,0);
//I don't want i or j is zero
//But if they are still zero , The program will still work normally
return 0;
}
There is no integer type without a 0. However, you can provoke a compiler error by introducing a conversion to a pointer type. Its a bit hacky, but achieves what you want (I think) for a literal 0:
#include <iostream>
struct from_int {
int value;
from_int(int value) : value(value) {}
};
struct non_zero {
int value;
non_zero(int*) = delete;
non_zero(from_int f) : value(f.value) {}
};
void bar(non_zero n) {
int i = n.value; // cannot be 0
}
int main() {
bar(non_zero(42));
//bar(non_zero(0)); // compiler error
}
bar is the function that cannot be called with a 0 parameter. 0 can be converted to a pointer but that constructor has no definition. Any other int will pick the other constructor. Though it requires the caller to explicitly construct a non_zero because only one user defined conversion is taken into account.
Note that this only works for a literal 0. There is no error when you pass a 0 to this function:
void moo(int x){
bar(non_zero(x));
}
Thats why it should be considered as a hack. Though, in general it is not possible to trigger a compiler error based on the value of x which is only known at runtime.
If you want to throw an exception, thats a whole different story. You'd simply add a check in the function:
if (i == 0) throw my_custom_exception{"some error message"};
If you are using only MSVC you can also take a look at Structured Annotation Language (SAL). It is described on MSDN.
For your case you might be interested in _In_range_(lb,ub). An example would be:
void f(_In_range_(1,300) int a, _In_range_(1, 2147483647) int b);
Please note that this will not prohibit calling f(0, 0) but code analysis will trigger a warning. That warning will be triggered also in cases where you call f(x,x) and the compiler knows that x is zero.
In the past I liked to use SAL as it makes the interface clearer and can help reveal errors because the compiler can check more semantics. But now with modern C++ und the CppCoreGuidelines I am trying to follow the guidelines and so normally I don't need SAL anymore.

Porting structs to MSVC 2017

how can I port the following Linux declaration to MSVC? "Expected identifier" is what I get as an error.
static const struct tap_align_size align_size_000000_00[] = {
[0] = {.align = 1,.size = 4, },
[52] = {.align = 1,.size = 4, },
};
where
struct tap_align_size {
uint8_t align:4, size:4;
};
You would have to make a struct with a constructor (with an array within) or laboriously type {} 51 times. The latter possibility is more risky because you do not know the order of fields in the struct, and even if you knew, a newer version could shuffle them, with the compiler unable to detect the change.

C++ enum definitions not being accepted

I would like to use some nss3.dll code in my program. To do this I decided to declare all of the compound datatypes that it needs and call the functions inside the dll file with them.
I am using a file in the firefox source code to see how to properly use the functions I need. In one of the functions it declares one of these compound datatypes (secuPWData) and passes it variables. Here is the definition I pasted into my code without any errors:
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
The declaration of this struct looks like this in the code I'm looking at: secuPWData pwdata = { PW_NONE, NULL };
When I try to use a similar (or even the same) declaration, it complains about the PW_NONE attribute, claiming it is undefined. When I tried to pass in the 0 value in its place, it told me that 'a value of type "int" cannot be used to initialize an entity of type "enum secuPWData::"'. To try to debug the issue, I tried pasting the definition right on top of the declaration, without any change.
What is causing this problem to occur?
Thanks for any help.
just as #n.m. mentioned try using secuPWData::PW_NONE
#include <iostream>
using namespace std;
typedef struct {
enum {
PW_NONE = 0,
PW_FROMFILE = 1,
PW_PLAINTEXT = 2,
PW_EXTERNAL = 3
} source;
char *data;
} secuPWData;
int main() {
secuPWData pwdata = { secuPWData::PW_NONE, NULL };
return 0;
}
worked for me .. ideone - link

Are there any scenarios where C4172 Visual C++ warning should not be considered an error?

There's C4172 Visual C++ warning for cases when a function returns an address of a local or temporary or a reference to a local variable.
Something like this:
int& fun()
{
int var;
return var; //C4172
}
Now looks like it is a good idea to use #pragma warning to make Visual C++ treat C4172 as error and break compilation.
Are there any sane scenarios where C4172 is not actually an error?
I'm not sure why anyone would ever want to do this:
int * stackTester()
{
int dummy;
return &dummy;
}
bool stackGoesUp()
{
int dummy;
return stackTester() > &dummy;
}
But generally speaking, you should treat the warning like an error.
It is a level 1 warning, very hard to ignore. But the compiler is following language standards here, invoking UB is not forbidden. And it is a very common bug that too often does come to a good end. The pointed-to stack location stays stable as long as you don't make any function calls.
The best way to deal with this is to always turn warnings into errors. Compile with /WX, "Treat warnings as errors" setting in the IDE. If you then intentionally want to suppress a warning then #pragma warning makes it clear to everybody that something fishy is going on that was thought about and not an accident.
Unused code
class base
{
virtual blah& makeBlah()
}
class red : public base
{
blah& makeBlah() { return blah(); } // there are no red blahs, never called
}
class blue : public base
{
blah& makeBlah() { actual code to make a blah }
}

What could cause initialization order to corrupt the stack?

Question is in bold below :
This works fine:
void process_batch(
string_vector & v
)
{
training_entry te;
entry_vector sv;
assert(sv.size() == 0);
...
}
However, this causes the assert to fail :
void process_batch(
string_vector & v
)
{
entry_vector sv;
training_entry te;
assert(sv.size() == 0);
...
}
Now I know this issue isn't shrink wrapped, so I'll restrict my question to this: what conditions could cause such a problem ? Specifically: variable initialization getting damaged dependant on appearance order in the stack frame. There are no malloc's or free's in my code, and no unsafe functions like strcpy, memcpy etc... it's modern c++. Compilers used: gcc and clang.
For brevity here are the type's
struct line_string
{
boost::uint32_t line_no;
std::string line;
};
typedef std::vector<boost::uint32_t> line_vector;
typedef std::vector<line_vector> entry_vector;
typedef std::vector<line_string> string_vector;
struct training_body
{
boost::uint32_t url_id;
bool relevant;
};
struct training_entry
{
boost::uint32_t session_id;
boost::uint32_t region_id;
std::vector< training_body> urls;
};
p.s., I am in no way saying that there is a issue in the compiler, it's probably my code. But since I am templatizing some code I wrote a long time ago, the issue has me completely stumped, I don't know where to look to find the problem.
edit
followed nim's suggestion and went through the following loop
shrink wrap the code to what I have shown here, compile and test, no problem.
#if 0 #endif to shrink wrap the main program.
remove headers till it compiles in shrink wrapped form.
remove library links till compiles in shrink wrapped form.
Solution: removing link to protocol buffers gets rid of the problem
The C++ standard guarantees that the following assertion will succeed:
std::vector<anything> Default;
//in your case anything is line_vector and Default is sv
assert(Default.size() == 0);
So, either you're not telling the whole story or you have a broken STL implementation.
OR: You have undefined behavior in your code. The C++ standard gives no guarantees about the behavior of a program which has a construct leading to UB, even prior to reaching that construct.
The usual case for this when one of the created objects writes beyond
its end in the constructor. And the most frequent reason this happens
in code I've seen is that object files have been compiled with different
versions of the header; e.g. at some point in time, you added (or
removed) a data member of one of the classes, and didn't recompile all
of the files which use it.
What might cause the sort of problem you see is a user-defined type with a misbehaving constructor;
class BrokenType {
public:
int i;
BrokenType() { this[1].i = 9999; } // Bug!
};
void process_batch(
string_vector & v
)
{
training_entry te;
BrokenType b; // bug in BrokenType shows up as assert fail in std::vector
entry_vector sv;
assert(sv.size() < 100);
...
}
Do you have the right version of the Boost libaries suited for your platform? (64 bit/32 bit)? I'm asking since the entry_vector object seems to be have a couple of member variables of type boost::uint32_t. I'm not sure what could be the behaviour if your executable is built for one platform and the boost library loaded is of another platform.