Shachar Shemesh wrote:

Hi all,

Here is a small program for your viewing pleasure:

class a {
public:
    explicit a(int param);

    a &operator= ( a &that );
};

int main()
{
    a var1(3);

    var1=a(5);

    return 0;
}


Somewhat surprisingly, this does not compile:
g++ -Wall -g    testcompile.cc -o testcompile
testcompile.cc: In function `int main()':
testcompile.cc:12: error: no match for 'operator=' in 'var1 = a(5)'
testcompile.cc:5: error: candidates are: a& a::operator=(a&)
make: *** [testcompile] Error 1

There are two things that can make it compile. One is to add a "const" at the "operator=" definition, and the other is to use an explicit variable (i.e. - not a temporary one).

The reason for this failure seems to be that g++ treats temporary variables as consts. I see neither reason nor logic for this decision, however. Why can't I modify temporary variables if I so wish? Don't they have a well defined life span (until the end of the statement) for a reason?

         Shachar


To summarize the thread:
The above does not work because temporary nameless variables are a hybrid between const and non-const. You can call non-const methods of the var, but you cannot bind it to a non-const reference.


To understand the solution, we must understand what we're trying to do here. The most common case where we want something like this is when the class has "ownership" over the data. For example - auto_ptr (an STL construct) has ownership over the pointer. Whoever is the owner is the one who gets to destroy the data when the class is destroyed. This owenership is passed on when copy or assignment happens.

The trick is to use a proxy struct, that simply holds the information while in transit between copy source and destination. This struct has enough relevant data. In auto_ptr's case, this is just the pointer we guard.

following auto_ptr's example, we will have a function called "release", that will return the relevant data (the pointer) and disown it, but not destroy the original (only remove owenership). If we only have a single scalar to pass around, this is adequate. If we need more than a single scalar, we can use the proxy struct directly to pass the info around, and make the "release" function private.

So, without further ado, here is it:
class a {
   int member1, member2;

  bool owner;

  struct a_export {
         int member1, member2;

         a_export( int m1, int m2 ) : member1(m1), member2(m2) {}
   }
public:
// This part as before
   explicit a(int param);

   a &operator= ( a &that );

   a &operator= ( a_export proxy ) // Notice - not a reference
   {
      member1=proxy.member1;
      member2=proxy.member2;

      owner=true;

      return *this;
   }
   operator a_export() // Notice - not const function
   {
       a_export tmp( member1, member2 );
      owner=false;

      return tmp;
   }
};

If you compile this code, you will find that "main" now works as it was, without a problem.

Explanation: The operator to convert a to a_export (implicitly) is not const, but we said it's ok to run non-const methods on temporary vars. This, of course, creates a temporary var of type a::a_export. Then, notice how the operator= accepts a copy (you can probably also bind it to "const a_export &"). We are trusting here the fact that all methods to manipulate a_export must be in a (as a_export is private), and we therefor give up ownership before anybody else picks it up.

This will fail if you write a line in main saying "static_cast<a::a_export>(var1);". var1 will lose owenership to a temporary variable, which will not be picked up by anyone else, and resources will leak. Short solution - don't write such lines :-(.

Like I said above - ugly. I'd rather just be able to work with the temporaries directly.

         Shachar

--
Shachar Shemesh
Lingnu Open Source Consulting ltd.
http://www.lingnu.com/


================================================================= To unsubscribe, send mail to [EMAIL PROTECTED] with the word "unsubscribe" in the message body, e.g., run the command echo unsubscribe | mail [EMAIL PROTECTED]



Reply via email to