C++ use of explicit suggested by cppcheck - c++

Is using the cast constructor bad?
Otherweise why a code quality checker (cppcheck in my case) would constantly suggest to add explicit before single parameter constructors?
What if I want to do
class MyClass {
A(int) {}
};
A a = 1;
If I follow the "suggestions" and write
class MyClass {
explicit A(int) {}
};
A a = 1;
would throw an error, but if I use the first I'll have a warning that i've to document to pass the code reviews.

C++ Core Guidelines
C.46: By default, declare single-argument constructors explicit
Reason
To avoid unintended conversions.
Example, bad
class String {
public:
String(int); // BAD
// ...
};
String s = 10; // surprise: string of size 10
Exception
If you really want an implicit conversion from the constructor
argument type to the class type, don't use explicit:
class Complex {
public:
Complex(double d); // OK: we want a conversion from d to {d, 0}
// ...
};
Complex z = 10.7; // unsurprising conversion
See also: Discussion of implicit conversions

Such implicit class type conversion can be used easily without intention. With this converting constructor every function or member function which accepts MyClass as argument will accept also int. Therefore every int passed to such a function will be converted to a temporary MyClass which will be discarded after the function has finished. Probably not what you want.

Related

What is the point of declaring the constructor explicit in an empty struct?

I was browsing a GCC header file recently and found this:
struct defer_lock_t { explicit defer_lock_t() = default; };
Why is the constructor declared explicit versus just being an empty struct defer_lock_t {}?
My understanding is that this type is used with a constexpr for constructor overloading. I'm a bit fuzzy about the explicit keyword but I think I somewhat understand its function.
The point is that defer_lock_t construction is never implicit. While if the constructor was not declared as explicit it would participate in implicit construction.
Consider this example:
struct explicit_t { explicit explicit_t() = default; };
struct implicit_t { implicit_t() = default; };
void foo(explicit_t){}
void bar(implicit_t){}
int main() {
//foo({}); // implicit - error
foo(explicit_t{}); // explicit - ok
bar({}); // implicit - ok
bar(implicit_t{}); // explicit - ok
}
This can be desirable when explicit_t has important semantics that are needed to read and understand the code. Calling foo({}) might be dangerous, because the reader is not aware of what is actually passed to foo. It can also mitigate confusion when overload resolution is involved and it should be visible at the call site which overload is picked. Also consider that foo(explicit_t{}) will break when foos signature is changed, while foo({}) might silently do the wrong thing. There can be many reasons to make things explicit in code rather than implicit.

C++ constructor with declaration account(int =0);

class Act {
protected:
string Owner;
double Balance;
public:
explicit Act(int = 0);
double getBalance() { return Balance; };
};
What is the meaning of line of constructor Act(int =0); Need what int=0 would do here.
Explanation
explicit Act (int = 0);
defines a constructor, that construct an Act from an int parameter. The =0 means that if the parameter can be omitted, it will have a default value of 0. The explicit keyword tells the compiler not to use this constructor for making an implicit conversion.
Examples of use
As it is:
Act a1; // Will generate the same code as Act a1(0);
Act a5{}; // Same as above, but using the braced initialization
Act a2(12); // Obvious
Act a3=13; // Ouch ! Compiler error because of explicit
Act a4 = Act(13); // Ok, because now the call is explicit
If you wouldn't have the explicit keyword, then this line would be ok
Act a3=13; // If not explicit, this is the same than Act a3=Act(13);
Important remarks
The default value is not something that is part of the constructor itself, but a behavior that is defined on the caller side, based on the declaration of the constructor known by the caller.
This means that you could include declare the class with different default values in different compilation units. Although strange, this is perfectly valid.
Note that the absence of parameter name in the declaration is not a problem either, because, the parameter name can be declared within the constructor definition:
Act::Act(int x) : Balance((double)x) {
cout <<"Constructor Act with parameter "<<x<<endl;
}
Finally, note that if you want to use the default value by omitting the parameter, but that your constructor has only one parameter, you should either use the syntax form a1 or a5 in the examples above. You should however not use the syntax with empty parentheses because this would be understood as a function declaration:
Act a0(); // Ouch !! function declaration ! Use a0 or a0{} instead.
In order to address your question we must break down what the line does.
The line calls the constructor for the class Act, the int which has no variable name requires the constructor to take an int. However the =0 part is the default parameter telling the constructor that you don't need the int just place a 0 there.

Assignment operator=

Suppose I have a class called Complex with 2 parameters real and imag. I want to overload the =(assignment) operator so that I could copy the value from the real parameter and assign it to an int.
If my main would look something like;
Complex z(1, 2);
int a = z;
I want a to be equal to 1.
How can I implement this function/method?
Use cast operator:
//Declaraion
class Complex {
operator int();
}
//Definition
Complex::operator int() {
return real_number;
}
Cast operator can implicitly convert a class instance to a certain type that is defined. It is a handy tool, but sometimes can be dangerous and vulnerable, and hard to debug.
When you define the assignment operator you are instructing the compiler on what to do when a value of possibly a different type is assigned to and instance of your class.
In this case instead you want to define what to do when an instance of your class is assigned to a variable of a different non-class type and this is not possible however. In other words it's the receiving instance that defines what to do in case of an assignment and you can customize this only for class types.
Something quite similar is instead to define how an instance of your class should be convertible to another type, e.g. how to convert a complex to an integer, and this conversion will be used also in case of assignment:
struct complex {
double real, imag;
...
operator int () const { return int(real); }
};
It isn't ideal to have code that reads as an assignment of types from different equivalence classes. It is correct that one should use casting instead, but the casting must be made explicit in C++11:
struct Complex {
double r, i;
...
explicit operator int () const { return int(r); }
};
Complex c = { 1.1, 2.2 };
float a = c; // fails with explicit
float a = (float)c; // fails with explicit
int a = c; // fails with explicit
int a = (int)c; // compiles with explicit
Do you really need to define a class for complex? It's part of standard library
Even you can see <complex> (#include <complex>) to find the operators and definitions overloaded
See more here

How to prevent default initialization of a const variable with a class type

I have a custom class that I want to behave like a built-in type.
However I have noticed that you can initialise a const variable of that class without providing an initial value. My class currently has an empty default constructor.
Here is a comparison of int and my class foo:
int a; // Valid
int a = 1; // Valid
const int a = 1; // Valid
const int a; // Error
foo a; // Valid
foo a = 1; // Valid
const foo a = 1; // Valid
const foo a; // Should cause an error, but it compiles
As you can see I need to prevent
const foo a;
from compiling.
Any ideas from C++ gurus?
It compiles only if it has a default constructor, and it compiles because it has it, which means that it is initialized. If you don't want that line to compile, just disable the default constructor (will also make foo a; an error as an unwanted side effect). Without a definition of foo or what you want to do, this is as far as I can get.
I don't think there is any way of achieving what you want (i.e. allow the non-const variable to be default initialized, while having the const version fail compilation and allowing the other use cases --that require providing constructors)
The rules of C++ simply say that default-initialization (e.g. new T;) and value-initialization (e.g. new T();) are the same for objects of class type, but not for objects of fundamental type.
There's nothing you can do to "override" this distinction. It's a fundamental part of the grammar. If your class is value-initializable, then it is also default-initializable.
There is a sort-of exception for classes without any user-defined constructors: In that case, initialization of members is done recursively (so if you default-init the object, it tries to default-init all members), and this will fail if any of the class members are themselves fundamental, or again of this nature.
For example, consider the following two classes:
struct Foo { int a; int b; };
struct Goo { int a; int b; Goo(){} };
//const Foo x; // error
const Goo y; // OK
The implicit constructor for Foo is rejected because it doesn't initialize the fundamental members. However, y is happily default-initialized, and y.a and y.b are now "intentionally left blank".
But unless your class doesn't have any user-defined constructors, this information won't help you. You cannot "forward" the initialization type to a member (like Foo() : INIT_SAME_AS_SELF(a), b() { }).

Why is explicit allowed for default constructors and constructors with 2 or more (non-default) parameters?

I understand that constructors with one (non-default) parameter act like implicit convertors, which convert from that parameter type to the class type. However, explicit can be used to qualify any constructor, those with no parameters (default constructor) or those with 2 or more (non-default) parameters.
Why is explicit allowed on these constructors? Is there any example where this is useful to prevent implicit conversion of some sort?
One reason certainly is because it doesn't hurt.
One reason where it's needed is, if you have default arguments for the first parameter. The constructor becomes a default constructor, but can still be used as converting constructor
struct A {
explicit A(int = 0); // added it to a default constructor
};
C++0x makes actual use of it for multi parameter constructors. In C++0x, an initializer list can be used to initialize a class object. The philosophy is
if you use = { ... }, then you initialize the object with a sort of "compound value" that conceptually represents the abstract value of the object, and that you want to have converted to the type.
if you use a { ... } initializer, you directly call the constructors of the object, not necessarily wanting to specify a conversion.
Consider this example
struct String {
// this is a non-converting constructor
explicit String(int initialLength, int capacity);
};
struct Address {
// converting constructor
Address(string name, string street, string city);
};
String s = { 10, 15 }; // error!
String s1{10, 15}; // fine
Address a = { "litb", "nerdsway", "frankfurt" }; // fine
In this way, C++0x shows that the decision of C++03, to allow explicit on other constructors, wasn't a bad idea at all.
Perhaps it was to support maintainance. By using explicit on multi-argument constructors one might avoid inadvertently introducing implicit conversions when adding defaults to arguments. Although I don't believe that; instead, I think it's just that lots of things are allowed in C++ simply to not make the language definition more complex than it already it is.
Perhaps the most infamous case is returning a reference to non-static local variable. It would need additional complex rules to rule out all the "meaningless" things without affecting anything else. So it's just allowed, yielding UB if you use that reference.
Or for constructors, you're allowed to define any number of default constructors as long as their signatures differ, but with more than one it's rather difficult to have any of them invoked by default. :-)
A better question is perhaps, why is explicit not also allowed on conversion operators?
Well it will be, in C++0x. So there was no good reason why not. The actual reason for not allowing explicit on conversion operators might be as prosaic as oversight, or the struggle to get explicit adopted in the first place, or simple prioritization of the committee's time, or whatever.
Cheers & hth.,
It's probably just a convenience; there's no reason to dis-allow it, so why make life difficult for code generators, etc? If you checked, then code generation routines would have to have an extra step verifying how many parameters the constructor being generated has.
According to various sources, it has no effect at all when applied to constructors that cannot be called with exactly one argument.
According to the High Integrity C++ Coding Standard you should declare all sinlge parameter constructor as explicit for avoiding an incidentally usage in type conversions. In the case it is a multiple argument constructor suppose you have a constructor that accepts multiple parametres each one has a default value, converting the constructor in some kind of default constructor and also a conversion constructor:
class C {
public:
C( const C& ); // ok copy
constructor C(); // ok default constructor
C( int, int ); // ok more than one non-default argument
explicit C( int ); // prefer
C( double ); // avoid
C( float f, int i=0 ); // avoid, implicit conversion constructor
C( int i=0, float f=0.0 ); // avoid, default constructor, but
// also a conversion constructor
};
void bar( C const & );
void foo()
{
bar( 10 ); // compile error must be 'bar( C( 10 ) )'
bar( 0.0 ); // implicit conversion to C
}
One reason to explicit a default constructor is to avoid an error-prone implicit conversion on the right hand side of an assignment when there is an overload to class_t::operator= that accepts an object with type U and std::is_same_v<U, class_t> == false. An assignment like class_t_instance = {} can lead us to an undesirable result if we have, for example, an observable<T> that overloads the move assignment operator to something like observable<T>::operator=(U&&), while U should be convertible to T. The confusing assignment could be written with an assignment of a default constructed T (observed type object) in mind, but in reality the programmer is "erasing" the observable<T> because this assignment is the same as class_t_instance = class_t_instance{} if the default constructor is implicit. Take a look at a toy implementation of an observable<T>:
#include <boost/signals2/signal.hpp>
#include <iostream>
#include <type_traits>
#include <utility>
template<typename T>
struct observable {
using observed_t = T;
//With an implicit default constructor we can assign `{}` instead
//of the explicit version `observable<int>{}`, but I consider this
//an error-prone assignment because the programmer can believe
//that he/she is defining a default constructed
//`observable<T>::observed_t` but in reality the left hand side
//observable will be "erased", which means that all observers will
//be removed.
explicit observable() = default;
explicit observable(observed_t o) : _observed(std::move(o)) {}
observable(observable&& rhs) = default;
observable& operator=(observable&& rhs) = default;
template<typename U>
std::enable_if_t<
!std::is_same_v<std::remove_reference_t<U>, observable>,
observable&>
operator=(U&& rhs) {
_observed = std::forward<U>(rhs);
_after_change(_observed);
return *this;
}
template<typename F>
auto after_change(F&& f)
{ return _after_change.connect(std::forward<F>(f)); }
const observed_t& observed() const noexcept
{ return _observed; }
private:
observed_t _observed;
boost::signals2::signal<void(T)> _after_change;
};
int main(){
observable<int> o;
o.after_change([](auto v){ std::cout << "changed to " << v << std::endl; }); //[1]
o = 5;
//We're not allowed to do the assignment `o = {}`. The programmer
//should be explicit if he/she desires to "clean" the observable.
o = observable<int>{};
o = 10; //the above reaction [1] is not called;
//outputs:
//changed to 5
}