Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are implicit conversions good or bad in modern C++?

In this proposal:

N3830 Scoped Resource - Generic RAII Wrapper for the Standard Library

a scoped_resource RAII wrapper is presented.

On page 4, there is some code like this:

auto hFile = std::make_scoped_resource(
      ...
    );    
...

// cast operator makes it seamless to use with other APIs needing a HANDLE
ReadFile(hFile, ...);

The Win32 API ReadFile() takes a raw HANDLE parameter, instead hFile is an instance of scoped_resource, so to make the above code work, there is an implicit cast operator implemented by scoped_resource.

But, wasn't the "modern" recommendation to avoid these kind of implicit conversions?

For example, ATL/MFC CString has an implicit conversion (cast operator) to LPCTSTR (const char/wchar_t*, i.e. a raw C-string pointer), instead STL strings have an explicit c_str() method.

Similarly, smart pointers like unique_ptr have an explicit get() method to access the underlying wrapped pointer; and that recommendation against implicit conversion seems also present in this blog post:

Reader Q&A: Why don’t modern smart pointers implicitly convert to *?

So, are these implicit conversions (like ATL/MFC CString and the newly proposed scoped_resource) good or not for modern C++?

From a coding perspective, I'd say that being able to simply directly pass a RAII wrapper - be it CString or scoped_resource - to a C API expecting a "raw" parameter (like a raw C string pointer, or raw handle), relying on implicit conversions, and without calling some .GetString()/.get() method, seems very convenient.

like image 246
Mr.C64 Avatar asked Mar 04 '14 00:03

Mr.C64


People also ask

Is implicit type conversion bad?

Everyone knows Implicit Conversion is bad. It can ruin SARGability, defeat index usage, and burn up your CPU like it needs some Valtrex.

Does C allow implicit conversion?

Implicit Type Conversion is also known as 'automatic type conversion'. It is done by the compiler on its own, without any external trigger from the user. It generally takes place when in an expression more than one data type is present.

What are the advantages of type conversion?

Advantages of Type Conversion: This is done to take advantage of certain features of type hierarchies or type representations. It helps to compute expressions containing variables of different data types.

What happens in implicit conversion?

An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.


1 Answers

Below is quote from C++ Primer 5th edition.

Caution: Avoid Overuse of Conversion Functions

As with using overloaded operators, judicious use of conversion operators can greatly simplify the job of a class designer and make using a class easier. However, some conversions can be misleading. Conversion operators are misleading when there is no obvious single mapping between the class type and the conversion type.

For example, consider a class that represents a Date. We might think it would be a good idea to provide a conversion from Date to int. However, what value should the conversion function return? The function might return a decimal representation of the year, month, and day. For example, July 30, 1989 might be represented as the int value 19800730. Alternatively, the conversion operator might return an int representing the number of days that have elapsed since some epoch point, such as January 1, 1970. Both these conversions have the desirable property that later dates correspond to larger integers, and so either might be useful.

The problem is that there is no single one-to-one mapping between an object of type Date and a value of type int. In such cases, it is better not to define the conversion operator. Instead, the class ought to define one or more ordinary members to extract the information in these various forms.

So, what I can say is that in practice, classes should rarely provide conversion operators. Too often users are more likely to be surprised if a conversion happens automatically than to be helped by the existence of the conversion. However, there is one important exception to this rule of thumb: It is not uncommon for classes to define conversions to bool. Under earlier versions of the standard, classes that wanted to define a conversion to bool faced a problem: Because bool is an arithmetic type, a class-type object that is converted to bool can be used in any context where an arithmetic type is expected. Such conversions can happen in surprising ways. In particular, if istream had a conversion to bool, the following code would compile:

int i = 42;
cin << i; // this code would be legal if the conversion to bool were not explicit!

You should use explicit conversion operators. Below is a little example:

class small_int 
{
private: 
  int val;
public:
  // constructors and other members
  explicit operator int() const { return this->val; }
}

... and in the program:

int main()
{
  SmallInt si = 3; // ok: the SmallInt constructor is not explicit
  si + 3; // error: implicit is conversion required, but operator int is explicit
  static_cast<int>(si) + 3; // ok: explicitly request the conversion

  return 0;
}
like image 170
Victor Avatar answered Sep 17 '22 12:09

Victor