views:

81

answers:

4

Greetings, everyone!

I have a class that receives a pointer to a "circle" (for example) and then adjusts its attributes via some "chaining" methods. Something like this:

class CCircleSetter
{
public:
   explicit CCircleSetter( CCirclePtr circle ) : m_circle(circle)
   {
   }

   CCircleSetter & Radius( int radius )
   {
       if (m_circle) m_circle->SetAttribute( "radius", radius );
       return *this;
   }
   CCircleSetter & Center( CPoint center )
   {
       if (m_circle) m_circle->SetAttribute( "center", center );
       return *this;
   }

   operator bool() const
   {
      return ( m_circle != NULL );
   }

private:
   CCirclePtr m_circle;
};

Now I wonder whether this code is legal or not:

if ( CCircleSetter(myCircle).Radius(10).Center(myPoint) ) 
{ ... }

On the one hand, I think that temporary object, created inside "if" expression, will live until the end of this expression. So, the calls to "Radius" and "Center" are legal. But on the other hand, it is an undefined behavior to use references to temporary variables and it seems to me that I am doing exactly this kind of thing - using (*this), where "this" is a temporary. It gives me some doubts, so, please, clarify. Thanks!

A: 

I don't think it's that a reference to a temporary is undefined, it's just forbidden. Also, I believe this only applies to function arguments. Visual Studio will allow you to pass references to non-const temporaries on the default warning/error level, though I know gcc will not.

As far as I know, doing so is only forbidden so programmers don't shoot themselves in the foot by storing a reference to a temporary that goes out of scope. Considering this is C++, I find that quite stupid.

I don't see any problem with what you're doing.

dauphic
+1  A: 

Even if it's a temporary variable, that doesn't mean that all of its members are temporary. Inside the scope of your temp object, the this pointer and other members are not temporary. Your code is completely fine. Now if you did something like:

SomeFunc(&CCircleSetter(myCircle))

this would be a reference to a temp variable.

tenfour
+1  A: 

No, that's fine in this very specific case, because the temporary will be destroyed AFTER the whole line will execute, but in general is very bad to hold references to temporaries.

Matias Valdenegro
"temporary will be destroyed AFTER the whole line will execute" - that's exactly what I wanted to hear. Any references to the standard?
SadSido
A: 

What you're doing is basically the same as in

if( istrm >> a >> b ) ...

which is the same as

if( istream.operator>>(a).operator>>(b).operator some_bool_like_type() )

I think this is fine from a usability POV. (There certainly are no syntactic/semantic problems with it.)

However, as always, implicit conversion to bool is a bit nasty, because it allows unexpected code to compile:

if ( CCircleSetter(myCircle).Radius(10) != 10 )
sbi
yes, the same thing. But in this example istream is not a variable, created inside "if" expression - no constructor / destructor for istream called. That was the point of my question.As for the unexpected code: is (true != 10) a legal expression?
SadSido
@SadSido: `bool` implicitly converts to `int`, so I think this should compile. But even if it doesn't, `operator bool` is a mean beast. I once came across a smart pointer implementation where the creators had forgotten to overload `<`. When you stuffed them into a `std::map`, its `operator bool` came to the "rescue", and the map compared the results of that. An empty pointer was smaller than a non-empty one, and all nun-empty ones were the same. So you ended up with maximal 2 items in the map. That took a while to debug until I found the missing comparison operators...
sbi