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 32,594 of 33,346   
   Cassio Neri to All   
   Re: Move, std::vector and gcc: which is    
   18 Oct 12 12:57:55   
   
   From: cassio.neri@googlemail.com   
      
   > In other words, when both copy and move are defined explicitly, the   
   > copy constructor gets called but if the move constructor is   
   > defaulted, then it gets called in preference to the copy   
   > constructor.   
   >   
   > I would have expected the GCC 4.6 behaviour to be correct. Am I   
   > mistaken?   
      
   I think GCC 4.7 is correct and GCC 4.6 is not. I also believe (to be   
   checked) that the issue here is exception safety. When you increases   
   the vector capacity the elements must be copied or moved to the new   
   memory buffer. Let's consider the two possibilities:   
      
   1) Elements are copied.   
      
   That is, each element is copied into the new buffer. Suppose the   
   vector has successfully copied the first element to the new buffer and   
   now is copying the second element. What happens, from the exception   
   point of view, if the copy constructor throws? Only a copy of the   
   first element was made and the original is still there. Then, the   
   vector can deliver the strong exception guarantee.   
      
   2) Elements are moved.   
      
   That is, each element is moved into the new buffer. Suppose the vector   
   has successfully moved the first element to the new buffer and now is   
   moving the second element. What happens, from the exception point of   
   view, if the move constructor throws? The first element was moved from   
   its original position and is no longer there. As an attempt to stick to   
   the strong safety guarantee, the vector could try to move the first   
   element back from the new buffer to where it used to be. However, this   
   operation might also throw and things get worse. Therefore, in this   
   case, the vector cannot provide the strong safety guarantee.   
      
   What's is happening then? If T has just either a copy or a move   
   constructor, then vector has no choice and must use what is   
   available. If both are available, vector favors the strongest safe   
   guarantee over performance and will copy unless it knows that T's move   
   constructor doesn't throw.   
      
   I guess, in this particular case, the implicitly defined move   
   constructor is marked as noexcept (that is, it doesn't throw) whereas   
   the one provided by you is not.   
      
   Change Both's move constructor to:   
      
   Both(Both&&) noexcept   
   {   
            cout << "Move\n";   
   }   
      
   then compile and run again. I think it GCC 4.7 will call your move   
   constructor this time.   
      
   A last not of caution: noexcept is not that simple. Hence, don't start   
   yet adding noexcept to all your functions that you ***believe*** don't   
   throw.  If you are wrong and the function does throw, then   
   std::terminate will be called. As far as I can tell, there's still a   
   lot of controversy on how to use noexcept safely. It might be worth   
   waiting a bit more when the gurus will come up with good guidelines   
   for us all.   
      
   HTH,   
   Cassio.   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- 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