home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 33,144 of 33,346   
   frank67x@googlemail.com to All   
   Re: post-increment without temporary obj   
   24 Jul 13 23:53:14   
   
   { Please limit your text to fit within 80 columns, preferably around 70,   
     so that readers don't have to scroll horizontally to read each line.   
     This article has been reformatted manually by the moderator. -mod }   
      
   Am Donnerstag, 25. Juli 2013 01:06:00 UTC+2 schrieb Daniel Krügler:   
   > Am 24.07.2013 20:42, schrieb frank67x@googlemail.com:   
   > > Trying to avoid a temporary copy of *this in post-increment.   
   > > But is this code below valid?   
   >   
   > Valid in which sense? Let's ignore for the moment the fact, that it is   
   > (in general) possible that operator++() may throw an exception (I'm   
   > mentioning this, because this would be a show stopper when considering   
   > to use this idiom in a general iterator facade such as   
   > boost::iterator_facade).   
      
   Ups - you're right. For delaying the operation that way, i can't catch in the   
   operator function anymore. So the delayed operation has to be w/o exceptions   
   (however see other (simpler) version below - it could catch on struct Delay).   
      
   > If I understand your idea, you want to create   
   > an UPInt object before you perform the incrementation, but that does not   
   > need your Lazy type, because I simply could construct UPInt from *this,   
   > after this would invoke pre-increment, and then return the value.   
      
   No, i want to avoid the temporary object - not create before.   
      
   > Whether you construct a named UPInt object (as I described above) or an   
   > unnamed one (in your design), in both cases, RVO is optional (but   
   > possible), so I don't see that you exclude the possibility of an   
   > intermediate copy (nor do I understand the advantage of preventing this)   
   > in either case.   
      
     g++ -fno-elide-constructors -O0 -o Lazy main.cpp   
      
   standard implementation with named temporary object:   
      
     x = 1   
     pre-increment   
     x = 2   
     before post-increment operation...   
     copy c'tor   
     pre-increment   
     copy c'tor   
     copy c'tor   
     y = 2   
     x = 3   
      
      
   "lazy" version:   
      
     x = 1   
     pre-increment   
     x = 2   
     before post-increment operation...   
     post-increment before exit   
     copy c'tor   
     DoIncrement()   
     pre-increment   
     copy c'tor   
     y = 2   
     x = 3   
      
   So saves one copy c'tor invocation.   
   However you're right (N)RVO does the job.   
   (I've to test, if (N)RVO still works, if the operation become more complex.)   
      
   > I also think that your model iterator UPInt doesn't properly account for   
   > some very special characteristics of a valid input iterator: The input   
   > iterator requirements basically allow you to implement an iterator where   
   > all copies reference the same underlying data source (e.g. an input   
   > stream) without need to copy it. Now if your UInt type would hold such a   
   > reference, you would have the problem that the also required operation   
   >   
   > *r++   
   >   
   > cannot be correctly implemented (without an additional proxy return   
   > type), because here you would invoke operator* *after* operator++(int),   
   > and the returned value is the wrong one (it would be the value that   
   > followed the required one).   
      
   Why? - it's still the same value in the output.   
   The delayed operation still belongs to operator++(int). It's just somehow in   
   between the return operation and actually escaping from the operator++(int).   
      
   > But maybe I misunderstand what you are intending here, so could you   
   > please make your point a little bit clearer?   
      
   Here is another version with boost::proto:   
      
   ===================================   
      
   #include    
      
   #include    
   using namespace boost;   
      
   template    
   class Lazy   
   {   
   private:   
           Expr const & _expr;   
      
   public:   
           Lazy(Expr const & expr)   
           : _expr(expr)   
           { }   
      
           ~Lazy()   
           {   
                   proto::eval(_expr, proto::default_context());   
           }   
      
   private:   
           Lazy(const Lazy &);   
      
   };   
      
   class UPInt; // forward declaration   
      
   template    
   void DoIncrement(SUBJECT * ptr)   
   {   
           std::cout << "DoIncrement()" << std::endl;   
           ++(*ptr);   
   }   
      
   class UPInt   
   {   
   private:   
           int _x;   
   public:   
           UPInt(   
                   int x)   
           : _x(x)   
           {}   
      
           UPInt (const UPInt & rhs)   
           : _x(rhs._x)   
           {   
                   std::cout << "copy c'tor" << std::endl;   
           }   
      
      
           UPInt & operator++()   
           {   
                   std::cout << "pre-increment" << std::endl;   
                   _x+=1;   
                   return *this;   
           }   
      
   #if 1   
           const UPInt operator++(int)   
           {   
                   typedef proto::result_of::make_expr<   
                           proto::tag::function,   
                           void(*)(UPInt*),   
                           UPInt *   
                   >::type const f_type;   
      
                   Lazy lazy(proto::make_expr<   
                           proto::tag::function>(   
                                   &DoIncrement,   
                                   this)   
                           );   
      
                   std::cout << "post-increment before exit" << std::endl;   
                   return *this;   
           }   
   #else   
           const UPInt operator++(int)   
           {   
           	UPInt old(*this);   
                   ++(*this);   
                   return old;   
           }   
      
   #endif   
      
           int operator()(void) const   
           {   
                   return _x;   
           }   
   };   
      
   std::ostream & operator<<(   
           std::ostream & lhs,   
           const UPInt & rhs)   
   {   
           lhs << rhs();   
           return lhs;   
   }   
      
   int main(int, char**)   
   {   
           UPInt x(1);   
           std::cout << "x = " << x << std::endl;   
      
           ++x;   
           std::cout << "x = " << x << std::endl;   
      
           std::cout << "before post-increment operation..." << std::endl;   
           UPInt y(x++);   
           std::cout << "y = " << y << std::endl;   
           std::cout << "x = " << x << std::endl;   
      
           return 0;   
   }   
      
   ===================================   
      
   And here a version w/o boost::proto:   
      
   ===================================   
      
   #include    
      
   class UPInt   
   {   
   private:   
           int _x;   
   public:   
           UPInt(   
                   int x)   
           : _x(x)   
           {}   
      
           UPInt (const UPInt & rhs)   
           : _x(rhs._x)   
           {   
                   std::cout << "copy c'tor" << std::endl;   
           }   
      
      
           UPInt & operator++()   
           {   
                   std::cout << "pre-increment" << std::endl;   
                   _x+=1;   
                   return *this;   
           }   
      
   #if 1   
           const UPInt operator++(int)   
           {   
                   struct Delay   
                   {   
                           UPInt* _ptr;   
      
                           Delay(UPInt * ptr)   
                           : _ptr(ptr)   
                           { }   
      
                           ~Delay()   
                           {   
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca