Safe type conversions with explicit conversion operators

Question | Dec 25, 2015 | nextptr 

By means of operator overloading, conversion constructors and conversion operators C++ empowers programmers to write generic code that can be used for both built-in primitive types and user-defined types. In "Mark constructor explicit to avoid implicit conversion" we discussed that how conversion constructor, albeit a useful feature, can introduce hard to find defects. Like conversion constructor, use of conversion operator is also full of pitfalls.

Let's take the classic unspecified bool idiom in reference to smart pointers. As smart pointers emulate the behaviors of raw pointers, it is required that, similar to raw pointers, they can be used in boolean contexts like if(ptr) { ... } and while(ptr) {...}. A seemingly straight forward implementation of this behavior is by using a bool conversion operator:

template <typename T>
class SmartPtr {
 public:

 SmartPtr(T* p)
    :raw(p) {  }

 operator bool () const {
    return raw != nullptr;
 }

 // More code including destructor..

 private:
 T* raw;
};    

// Create 2 pointers  
SmartPtr<int> sp1 = new int[10];
SmartPtr<float> sp2 = new float[10];

Above implementation would open possibilities for following - some unintended - use cases:

 if(sp1) { ... }  // OK
 if(sp1 && sp2) { .. }  // OK
 if(sp1 == sp2) { ... }  // Unintended, sp1 and sp2 are different types
 sp1 << 3;                // Unintended 
 int x = sp2 + 5;       // Unintended

To avoid some of these unintended conversions programmers resort to different alternates like using void* conversion operator:

 operator void* () const {
   return raw;
 }

More advanced techniques like Safe Bool Idiom, which is used in boost library's shared_ptr, are not so common. Details of Safe Bool Idiom are outside the scope of this discussion but I highly recommend you reading that article.

Finally, the C++11 standard specifies that like conversion constructors the conversion operators can also be marked explicit. If a conversion operator is marked explicit the conversion can only be done by explicit casting or implicitly to bool where ever "contextual conversion to bool" is applicable:

explicit operator bool () const {
    return raw != nullptr;
}

if(bool(sp1)) { ... }  // OK
if( sp1 == sp2 ) { .. } // Error
sp1 << 3;         // Error 

/* These implicit 
   "contextual bool conversions" 
   are OK too */
if(sp2) { .. }
if(sp1 && sp2) { ... }

Try solving a problem on this subject. Check out following implementation of MyArray:

template<typename T>
class MyArray {

 public:
  MyArray(const T* t, size_t size)
     :m_size(size) {
     m_arr = new T[m_size];
     memcpy(m_arr, t, sizeof(T)*m_size);
  }
  // subscript operator 
  T& operator [] (int index) {
     return m_arr[index];
  }    
  /* an explicit conversion operator that 
     returns raw pointer */
  explicit operator T* () {
     return m_arr;
  }
  size_t size() const { return m_size; }

 private:
  T* m_arr;
  size_t m_size;
};

// Using MyArray as String object
const char* hello = "Hello";
MyArray<char> str(hello,strlen(hello)+1);

Which one of the following use cases related to str is invalid and would not compile?

2015 nextptr