I use a struct to transfer data over TCP-IP and I have to stick with certain packet size, so I use char array of fixed size for text data. Due to the fact that I can't initialize it otherwise, I forced to copy string to that array in constructor using simple function (based on strcpy). The problem is: analyzer (clang-tidy Ubuntu LLVM 14.0.0) tells me
warning: constructor does not initialize these fields: receiver [cppcoreguidelines-pro-type-member-init]
but in fact that is not true. Tell me, please, how do I change my code to suppress those warnings messages? I understand, that I can initialize those arrays with zeros using {} and than fill them with the needed data, but it looks like double work..
inline void copyName(char *dst, const char *src) {
strncpy(dst, src, MAX_NAME_LENGTH);
}
struct Header {
const MessageType type;
char receiver[MAX_NAME_LENGTH];
static uint32_t messageId;
Header();
Header(MessageType type, const char* receiver);
};
Header::Header(const MessageType type, const char *receiverName)
: type(type) // the warning is here
{
copyName(receiver, receiverName);
Header::messageId++;
}
P.S> Found some workaround (which, of course, not the answer to the actual question): there is the option IgnoreArrays for that warning which, when set to true, suppresses those warnings
The warning is a false positive. The clang-tidy docs for the warning you got say:
The check takes assignment of fields in the constructor body into account but generates false positives for fields initialized in methods invoked in the constructor body.
https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.html
Seems like a poor check to me, but if you want to keep it enabled you might be able to suppress this one instance of it using the magic // NOLINT comment...somewhere?
Related
I have written a small wrapper for typeinfo to get the typecode of a variable at compile time more easily:
template<typename DataType>
class TypeInfo
{
public:
static const char* typecode()
{
DataType TypedVariable = 0;
const char* code = typeid(TypedVariable).name();
return(code);
};
};
I use it like this:
const char* code = TypeInfo<float>::typecode();
It compiles perfectly fine and works as expected, but I am getting the warning
src/common.hh(153): warning: variable "TypedVariable" was set but never used
detected during:
instantiation of "char TypeInfo<DataType>::typecode() [with DataType=r32]"
...
I am wondering why "calling" typeid() on a variable does not count as using it. I know that it is a defined keyword, but still I am irritated that getting the type of a variable does not count as using it.
The compilation is done using nvcc of CUDA 9.2. Maybe it is a CUDA specific thing?
Thanks for any help :)
//edit:
I made a mistake by not returning the full char* because I use only normal types! Thanks for making me aware of the typo! I also added the template definition. I forgot to copy that over!
Because you don't use the value of TypedVariable. You just use its type (and you can get it's type by rewriting your initialization as:
char const * const code = typeid(DataType).name();
This question already has answers here:
Default value of function parameter
(5 answers)
Closed 5 years ago.
What's the place for the default parameter value? Just in function definition, or declaration, or both places?
Default parameter values must appear on the declaration, since that is the only thing that the caller sees.
EDIT: As others point out, you can have the argument on the definition, but I would advise writing all code as if that wasn't true.
You can do either, but never both. Usually you do it at function declaration and then all callers can use that default value. However you can do that at function definition instead and then only those who see the definition will be able to use the default value.
C++ places the default parameter logic in the calling side, this means that if the default value expression cannot be computed from the calling place, then the default value cannot be used.
Other compilation units normally just include the declaration so default value expressions placed in the definition can be used only in the defining compilation unit itself (and after the definition, i.e. after the compiler sees the default value expressions).
The most useful place is in the declaration (.h) so that all users will see it.
Some people like to add the default value expressions in the implementation too (as a comment):
void foo(int x = 42,
int y = 21);
void foo(int x /* = 42 */,
int y /* = 21 */)
{
...
}
However, this means duplication and will add the possibility of having the comment out of sync with the code (what's worse than uncommented code? code with misleading comments!).
Although this is an "old" thread, I still would like to add the following to it:
I've experienced the next case:
In the header file of a class, I had
int SetI2cSlaveAddress( UCHAR addr, bool force );
In the source file of that class, I had
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
...
}
As one can see, I had put the default value of the parameter "force" in the class source file, not in the class header file.
Then I used that function in a derived class as follows (derived class inherited the base class in a public way):
SetI2cSlaveAddress( addr );
assuming it would take the "force" parameter as "false" 'for granted'.
However, the compiler (put in c++11 mode) complained and gave me the following compiler error:
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2
But when I added the default parameter in the header file of the base class:
int SetI2cSlaveAddress( UCHAR addr, bool force = false );
and removed it from the source file of the base class:
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )
then the compiler was happy and all code worked as expected (I could give one or two parameters to the function SetI2cSlaveAddress())!
So, not only for the user of a class it's important to put the default value of a parameter in the header file, also compiling and functional wise it apparently seems to be a must!
If the functions are exposed - non-member, public or protected - then the caller should know about them, and the default values must be in the header.
If the functions are private and out-of-line, then it does make sense to put the defaults in the implementation file because that allows changes that don't trigger client recompilation (a sometimes serious issue for low-level libraries shared in enterprise scale development). That said, it is definitely potentially confusing, and there is documentation value in presenting the API in a more intuitive way in the header, so pick your compromise - though consistency's the main thing when there's no compelling reason either way.
One more point I haven't found anyone mentioned:
If you have virtual method, each declaration can have its own default value!
It depends on the interface you are calling which value will be used.
Example on ideone
struct iface
{
virtual void test(int a = 0) { std::cout << a; }
};
struct impl : public iface
{
virtual void test(int a = 5) override { std::cout << a; }
};
int main()
{
impl d;
d.test();
iface* a = &d;
a->test();
}
It prints 50
I strongly discourage you to use it like this
the declaration is generally the most 'useful', but that depends on how you want to use the class.
both is not valid.
Good question...
I find that coders typically use the declaration to declare defaults. I've been held to one way (or warned) or the other too based on the compiler
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
using namespace std;
cout << nVal1 << << nVal2 << endl;
}
You may do in either (according to standard), but remember, if your code is seeing the declaration without default argument(s) before the definition that contains default argument, then compilation error can come.
For example, if you include header containing function declaration without default argument list, thus compiler will look for that prototype as it is unaware of your default argument values and hence prototype won't match.
If you are putting function with default argument in definition, then include that file but I won't suggest that.
Adding one more point. Function declarations with default argument should be ordered from right to left and from top to bottom.
For example in the below function declaration if you change the declaration order then the compiler gives you a missing default parameter error. Reason the compiler allows you to separate the function declaration with default argument within the same scope but it should be in order from RIGHT to LEFT (default arguments) and from TOP to BOTTOM(order of function declaration default argument).
//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK
int main() {
function("Using only one Default Argument", false, true);
function("Using Two Default Arguments", false);
function("Using Three Default Arguments");
return 0;
}
//definition
void function(char const *msg, bool three, bool two, bool one ) {
std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}
In C++ is perfectly legitimate to do:
bool x = "hi";
Because "hi" is translated by compiler to a char array and returns a pointer to that array, which is a number and number can be implicitly converted to bool (0 is false, anything else is true).
So I have these ctor:
Exception(QString Text, bool __IsRecoverable = true);
Exception(QString Text, QString _Source, bool __IsRecoverable = true);
Sadly I figured out that calling
Exception *e = new Exception("error happened", "main.cpp #test");
It creates a new instance of "Exception" class which is created using Exception(QString Text, bool __IsRecoverable = true); constructor, which is wrong to a point.
Is there a simple way to ensure that correct function is called, other than restructuring the constructors entirely, changing position of arguments, etc?
Firstly, I'm not sure why you're dynamically allocating an exception class. I'm not sure that's ever a good idea.
You can explicitly construct a QString:
Exception e("error happened", QString("main.cpp #test"));
Or you can pass the third argument:
Exception e("error happened", "main.cpp #test", true);
Or you can add an additional constructor that takes const char* and will be preferred over the conversion to bool:
Exception(QString Text, const char* Source, bool IsRecoverable = true);
You can easily make this forward to the QString version. Also note that names beginning with an underscore and a capital letter or with two underscores are reserved.
My suggestion would be to not use default arguments. They contribute to overload resolution problems like this, and anyway it is not very readable to just see true as an argument. Whoever's reading the code then has to stop and go look up what the true means. Even if it's yourself you may forget it in a few months time when you come back to the code, especially if you do this sort of thing a lot.
For example:
struct Exception: public whatever
{
Exception(char const *text);
Exception(char const *text, char const *source);
};
struct RecoverableException: public Exception
{
RecoverableException(char const *text);
RecoverableException(char const *text, char const *source);
};
It's a little bit more typing in this source file but the payoff is that your code which actually uses the exceptions is simpler and clearer.
To implement these constructors you could have them all call a particular function in the .cpp file with relevant arguments selecting which behaviour you want.
I have a preference for using char const * rather than QString as I am paranoid about two things:
unwanted conversions
memory allocation failure
If constructing a QString throws then things go downhill fast. But you may choose to not worry about this possibility because if the system ran out of memory and your exception handling doesn't prepare for that possibility then it's going to terminate either way.
I have some C++ code written in C-style.
For some reasons I can't use C++ string and IO libraries, so for strings handling I should use only functions like sprintf, itoa, etc.
I want to replace C-style which requires temporary buffers
char buf[12];
itoa(x, buf, 16);
set_some_text(buf);
by the following code
class i2a
{
public:
explicit i2a(int value) { ::sprintf(buf, "%d", value); }
operator const char* () const { return buf; }
private:
char buf[12];
};
// usage:
set_some_text(i2a(x));
(Such classes can be written for char<->wchar_t convertions, etc.)
I see some cases when such classes will be dangerous:
For example, one can write
const char* someMeaningfulName = i2a(x);
// the right code should be i2a someMeaningfulName(x); or i2a someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);
In more complex case, a function which accepts text will not copy it, but will save pointer to it somewhere. For example it may be
class Foo { .... const char* p; };
Foo f(const char* text) { ... foo.p = text; return foo; }
it can be really unobvious, unlike const char* variable.
Is there a way to make such classes more secure?
Upd: why not std::string, boost::lexical_cast, boost::format, etc :
The code should work when compiled with -fno-except (C++ exceptions disabled - no throw, no stack unwinding). Also it should keep working on low memory conditions.
std::string, streams uses heap-allocated memory and at least throws bad_alloc.
When we have no free heap memory, usually we still have some kilobytes of stack (for example to write to user that we are out of memory and then make proper cleanup).
ATL and MFC String Conversion Macros are also written in this way. Calling the constructor directly like i2a(x) will create a temporary object that will live until the function to which it is passed is complete. So here: do_some(i2a(x)), the temporary object will be there until do_some() is complete.
Refer the Example section (example 2) of this msdn document
Here,
const char* someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);
This will not work as, the temporary object will be freed on the first statement itself. someMeaningfulName will be garbage. If you feel that as lack of security, all I can say is:
That's how Microsoft does it!
You will always get somewhere into troubles if you use const char* for your local variables.
You will have the same with const char* someMeaningfulName = std::string("foo").c_str();
If you can you should declare your local variable like this :
i2a someMeaningfulName(x);
set_some_text(someMeaningfulName);
You can also consider adding a copy constructor to i2a to avoid sharing the buffer between two instances.
This question already has answers here:
Default value of function parameter
(5 answers)
Closed 5 years ago.
What's the place for the default parameter value? Just in function definition, or declaration, or both places?
Default parameter values must appear on the declaration, since that is the only thing that the caller sees.
EDIT: As others point out, you can have the argument on the definition, but I would advise writing all code as if that wasn't true.
You can do either, but never both. Usually you do it at function declaration and then all callers can use that default value. However you can do that at function definition instead and then only those who see the definition will be able to use the default value.
C++ places the default parameter logic in the calling side, this means that if the default value expression cannot be computed from the calling place, then the default value cannot be used.
Other compilation units normally just include the declaration so default value expressions placed in the definition can be used only in the defining compilation unit itself (and after the definition, i.e. after the compiler sees the default value expressions).
The most useful place is in the declaration (.h) so that all users will see it.
Some people like to add the default value expressions in the implementation too (as a comment):
void foo(int x = 42,
int y = 21);
void foo(int x /* = 42 */,
int y /* = 21 */)
{
...
}
However, this means duplication and will add the possibility of having the comment out of sync with the code (what's worse than uncommented code? code with misleading comments!).
Although this is an "old" thread, I still would like to add the following to it:
I've experienced the next case:
In the header file of a class, I had
int SetI2cSlaveAddress( UCHAR addr, bool force );
In the source file of that class, I had
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
...
}
As one can see, I had put the default value of the parameter "force" in the class source file, not in the class header file.
Then I used that function in a derived class as follows (derived class inherited the base class in a public way):
SetI2cSlaveAddress( addr );
assuming it would take the "force" parameter as "false" 'for granted'.
However, the compiler (put in c++11 mode) complained and gave me the following compiler error:
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2
But when I added the default parameter in the header file of the base class:
int SetI2cSlaveAddress( UCHAR addr, bool force = false );
and removed it from the source file of the base class:
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )
then the compiler was happy and all code worked as expected (I could give one or two parameters to the function SetI2cSlaveAddress())!
So, not only for the user of a class it's important to put the default value of a parameter in the header file, also compiling and functional wise it apparently seems to be a must!
If the functions are exposed - non-member, public or protected - then the caller should know about them, and the default values must be in the header.
If the functions are private and out-of-line, then it does make sense to put the defaults in the implementation file because that allows changes that don't trigger client recompilation (a sometimes serious issue for low-level libraries shared in enterprise scale development). That said, it is definitely potentially confusing, and there is documentation value in presenting the API in a more intuitive way in the header, so pick your compromise - though consistency's the main thing when there's no compelling reason either way.
One more point I haven't found anyone mentioned:
If you have virtual method, each declaration can have its own default value!
It depends on the interface you are calling which value will be used.
Example on ideone
struct iface
{
virtual void test(int a = 0) { std::cout << a; }
};
struct impl : public iface
{
virtual void test(int a = 5) override { std::cout << a; }
};
int main()
{
impl d;
d.test();
iface* a = &d;
a->test();
}
It prints 50
I strongly discourage you to use it like this
the declaration is generally the most 'useful', but that depends on how you want to use the class.
both is not valid.
Good question...
I find that coders typically use the declaration to declare defaults. I've been held to one way (or warned) or the other too based on the compiler
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
using namespace std;
cout << nVal1 << << nVal2 << endl;
}
You may do in either (according to standard), but remember, if your code is seeing the declaration without default argument(s) before the definition that contains default argument, then compilation error can come.
For example, if you include header containing function declaration without default argument list, thus compiler will look for that prototype as it is unaware of your default argument values and hence prototype won't match.
If you are putting function with default argument in definition, then include that file but I won't suggest that.
Adding one more point. Function declarations with default argument should be ordered from right to left and from top to bottom.
For example in the below function declaration if you change the declaration order then the compiler gives you a missing default parameter error. Reason the compiler allows you to separate the function declaration with default argument within the same scope but it should be in order from RIGHT to LEFT (default arguments) and from TOP to BOTTOM(order of function declaration default argument).
//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK
int main() {
function("Using only one Default Argument", false, true);
function("Using Two Default Arguments", false);
function("Using Three Default Arguments");
return 0;
}
//definition
void function(char const *msg, bool three, bool two, bool one ) {
std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}