2

Consider the code below and suppose that several years after; a colleague adds a new implementation of SetRotationSpeed(int i) in a DLL knowing that, the code of the class containing the implicit conversion has been compiled in static mode. There will be no compilation errors except that it may change the behavior of the program, which in my opinion constitutes a potential danger to the behavior of the program. Has the C++ standard thought about this edge effect? In this topic, I am not particularly interested in the use of the explicit keyword but in an edge effect that we can encounter on a program developed in the form of separated DLLs by several developers who do not necessarily know each the part developed by the other one.

#include <iostream>
#include <string>
using namespace std; 

class A
{
public:
   A(int n)
        : m_RotationalScannerSpeed(n/2)
    {
        std::cout << "Scanner Rotation speed"<<  m_RotationalScannerSpeed<<endl;
    }

private:
    int m_RotationalScannerSpeed;
};

void SetRotationSpeed(A a){

};

// Function added 2 years later by a collegue in a DLL... 
/*void SetRotationSpeed(int i){

};*/


int main (int argc, char* argv[])
{
    int i=5;
    SetRotationSpeed(i);
}
Landstalker
  • 1,368
  • 8
  • 9

1 Answers1

4

You should usually use explicit specifier to avoid such situations. When a constructor is marked explicit, no implicit conversions can be made using that constructor. Only explicit conversions are allowed, which is usually a good thing. Clang even has a nice warning about that:

Clang-Tidy: Single-argument constructors must be marked explicit to avoid unintentional implicit conversions

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • Thanks. I will think about using the keyword **explicit** more often in my code even if I liked that the behavior is the opposite : I mean indicate explicitly in the code (through a key word : implicit for example) that I wish to activate the implicit conversion because in most cases I do not want to have implicit conversion. – Landstalker Apr 03 '19 at 14:18
  • How exactly this solves a problem when implicit conversion is desirable? – Logman Apr 03 '19 at 14:19
  • @Logman the same way declaring variables `const` when you don't change them fixes undesired behavior when someone changes them. – Aykhan Hagverdili Apr 03 '19 at 14:22
  • @Ayxan but this is exactly oposite situation you want to change your variable declaring it const will prevent that. – Logman Apr 03 '19 at 14:35
  • @Logman if you always mark your constructors `explicit`, calls to the constructor, like in the question, must look like this `SetRotationSpeed(A(5))`. There's no way to interpret this as a call to a function which takes a single integer parameter, thus there's no problem. – Aykhan Hagverdili Apr 03 '19 at 14:39
  • @Ayxan Yes, but it may provide unnecessary code. I asume that you always use `std::string` constructor before passing cstring into a function or always explicite convert `int` to `long long` before assigning variable. – Logman Apr 03 '19 at 14:50
  • @Logman Well, `std::string` is meant to replace `char*` (you should generally only use `std::string`), and `int` is not a class. Your point is unclear. – Aykhan Hagverdili Apr 03 '19 at 14:53
  • @Ayxan I think you misunderstand my question. What if implicite conversion is intentional? You answer only part of OP question and you should point that. `explicit` is not a magic word that will solve all problems. There are types that intentionally do not declare constructors explicit for one reason or another. How to solve OP problem for such types should also be part of an answer. – Logman Apr 03 '19 at 15:13
  • @Logman I dont know if I understood well your question. For persons who can not change the constructor's declaration, one of the possible solutions is to change the prototype of the function in question; for exemple by using a call by reference `SetRotationSpeed(A& a)` and in this case, the call by an integer will not be accepted by the compiler. – Landstalker Apr 03 '19 at 15:53
  • @Ok I try to say this as simple as I can. What if you want to have implicit creation of an `A` object from `int`. You assumed that line `SetRotationSpeed(i);` should be ill formatted but it's not. OP want to prevent others from injecting code into his functions (intentionally or not). And not to prevent someone from unintentional type conversion. Type conversion is not a problem here. Argument deduction is. – Logman Apr 03 '19 at 22:27