C++ logical operators return value

c

Here is some code I'm writing in C++. There's a call to an addAVP() function

dMessage.addAVP(AVP_DESTINATION_HOST, peer->getDestinationHost() || peer->getHost());

which has two versions: one overloaded in the second parameter to addAVP(int, char*) and another to addAVP(int, int). I find the C++ compiler I use calls the addAVP(int, int) version which is not what I wanted since getDestinationHost() and getHost() both return char*.

Nonetheless the || operator is defined to return bool so I can see where my error is. Bool somehow counts as an integer and this compiles cleanly and calls the second addAVP().

Lately I'm using a lot of dynamically typed languages, i.e. lisp, where the above code is correct can be written without worries. Clearly, clearly the above code in C++ is a big error, but still have some questions:

  1. Should I be using this kind of shortcut, i.e. using the ||-operator's return value, at all in C++. Is this compiler dependent?

  2. Imagine that I really, really had to write the nice a || b syntax, could this be done cleanly in C++? By writing an operator redefinition? Without losing performance?

As a followup to my original request, or my own answer to 2 🙂 I was thinking along the lines of using a class to encapsulate the (evil?) rawpointer:

class char_ptr_w {
  const char* wrapped_;
public:
  char_ptr_w(const char* wrapped) : wrapped_(wrapped) {}
  char_ptr_w(char_ptr_w const& orig) {  wrapped_=orig.wrapped(); }
  ~char_ptr_w() {}
  inline const char* wrapped() const { return wrapped_; }
};

inline char_ptr_w operator||(char_ptr_w &lhs, char_ptr_w& rhs) {
  if (lhs.wrapped() != NULL)
    return char_ptr_w(lhs.wrapped());
  else
    return char_ptr_w(rhs.wrapped());
};

Then I could use:

char_ptr_w a(getDestinationHost());
char_ptr_w b(getHost());

addAVP(AVP_DESTINATION_HOST, a || b);

In which this addAVP would be overloaded for char_ptr_w. According to my tests, this generates at most the same assembly code as ternary a?b:c solution, particularly because of the NRVO optimization in the operator, which does not, in most compilers, call the copy-constructor (although you have to include it).

Naturally, in this particular example I agree that the ternary solution is the best. I also agree that operator redefinition is something to be taken with care, and not always beneficial. But is there anything conceptually wrong, in a C++ sense, with the above solution?

Best Answer

It is legal in C++ to overload the logic operators, but only if one or both of the arguments are of a class type, and anyway it's a very bad idea. Overloaded logic operators do not short circuit, so this may cause apparently valid code elsewhere in your program to crash.

return p && p->q;  // this can't possibly dereference a null pointer... can it?
Related Topic