vector.tcc (vector<>::_M_insert_aux): In C++0x mode, avoid a memory leak if the first...
authorPaolo Carlini <paolo.carlini@oracle.com>
Mon, 2 Jun 2008 12:22:53 +0000 (12:22 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Mon, 2 Jun 2008 12:22:53 +0000 (12:22 +0000)
2008-06-02  Paolo Carlini  <paolo.carlini@oracle.com>

* include/bits/vector.tcc (vector<>::_M_insert_aux): In C++0x mode,
avoid a memory leak if the first __uninitialized_move_a throws.
(vector<>::_M_fill_insert): Do not always copy to __x_copy, similarly
to _M_insert_aux.
* testsuite/23_containers/vector/modifiers/moveable.cc: Adjust.
* testsuite/23_containers/vector/resize/moveable.cc: Likewise.

From-SVN: r136277

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/vector.tcc
libstdc++-v3/testsuite/23_containers/vector/modifiers/moveable.cc
libstdc++-v3/testsuite/23_containers/vector/resize/moveable.cc

index 614d54c22e87f0b7f8331d6a7a9c4d056050842f..4f6b60491fce4d377dd855f55ed296ad95d5fe3b 100644 (file)
@@ -1,3 +1,12 @@
+2008-06-02  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * include/bits/vector.tcc (vector<>::_M_insert_aux): In C++0x mode,
+       avoid a memory leak if the first __uninitialized_move_a throws.
+       (vector<>::_M_fill_insert): Do not always copy to __x_copy, similarly
+       to _M_insert_aux.
+       * testsuite/23_containers/vector/modifiers/moveable.cc: Adjust.
+       * testsuite/23_containers/vector/resize/moveable.cc: Likewise.
+
 2008-05-31  Paolo Carlini  <paolo.carlini@oracle.com>
            Chris Jefferson  <chris@bubblescope.net>
 
index 030cb3aabccedd99e3db5a1a7e1ca09568469134..462d18f6cbb858c9f3c44a71a80d774ae30a72f6 100644 (file)
@@ -1,6 +1,6 @@
 // Vector implementation (out of line) -*- C++ -*-
 
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
 // Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
@@ -305,22 +305,29 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        {
          const size_type __len =
            _M_check_len(size_type(1), "vector::_M_insert_aux");
+         const size_type __elems_before = __position - begin();
          pointer __new_start(this->_M_allocate(__len));
          pointer __new_finish(__new_start);
          try
            {
+             // The order of the three operations is dictated by the C++0x
+             // case, where the moves could alter a new element belonging
+             // to the existing vector.  This is an issue only for callers
+             // taking the element by const lvalue ref (see 23.1/13).
+             this->_M_impl.construct(__new_start + __elems_before,
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
-             this->_M_impl.construct(__new_start + (__position - begin()),
                                      std::forward<_Args>(__args)...);
+#else
+                                     __x);
 #endif
+             __new_finish = 0;
+
              __new_finish =
                std::__uninitialized_move_a(this->_M_impl._M_start,
                                            __position.base(), __new_start,
                                            _M_get_Tp_allocator());
-#ifndef __GXX_EXPERIMENTAL_CXX0X__
-             this->_M_impl.construct(__new_finish, __x);
-#endif
              ++__new_finish;
+
              __new_finish =
                std::__uninitialized_move_a(__position.base(),
                                            this->_M_impl._M_finish,
@@ -329,7 +336,10 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
            }
          catch(...)
            {
-             std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
+             if (!__new_finish)
+               this->_M_impl.destroy(__new_start + __elems_before);
+             else
+               std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
              _M_deallocate(__new_start, __len);
              __throw_exception_again;
            }
@@ -351,15 +361,10 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
     {
       if (__n != 0)
        {
-#ifdef __GXX_EXPERIMENTAL_CXX0X__
-         value_type __x_copy = __x;
-#endif
          if (size_type(this->_M_impl._M_end_of_storage
                        - this->_M_impl._M_finish) >= __n)
            {
-#ifndef __GXX_EXPERIMENTAL_CXX0X__
              value_type __x_copy = __x;
-#endif
              const size_type __elems_after = end() - __position;
              pointer __old_finish(this->_M_impl._M_finish);
              if (__elems_after > __n)
@@ -392,22 +397,24 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
            {
              const size_type __len =
                _M_check_len(__n, "vector::_M_fill_insert");
+             const size_type __elems_before = __position - begin();
              pointer __new_start(this->_M_allocate(__len));
              pointer __new_finish(__new_start);
              try
                {
+                 // See _M_insert_aux above.
+                 std::__uninitialized_fill_n_a(__new_start + __elems_before,
+                                               __n, __x,
+                                               _M_get_Tp_allocator());
+                 __new_finish = 0;
+
                  __new_finish =
                    std::__uninitialized_move_a(this->_M_impl._M_start,
                                                __position.base(),
                                                __new_start,
                                                _M_get_Tp_allocator());
-#ifdef __GXX_EXPERIMENTAL_CXX0X__
-                 std::__uninitialized_fill_n_a(__new_finish, __n, __x_copy,
-#else
-                 std::__uninitialized_fill_n_a(__new_finish, __n, __x,
-#endif
-                                               _M_get_Tp_allocator());
                  __new_finish += __n;
+
                  __new_finish =
                    std::__uninitialized_move_a(__position.base(),
                                                this->_M_impl._M_finish,
@@ -416,8 +423,13 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
                }
              catch(...)
                {
-                 std::_Destroy(__new_start, __new_finish,
-                               _M_get_Tp_allocator());
+                 if (!__new_finish)
+                   std::_Destroy(__new_start + __elems_before,
+                                 __new_start + __elems_before + __n,
+                                 _M_get_Tp_allocator());
+                 else
+                   std::_Destroy(__new_start, __new_finish,
+                                 _M_get_Tp_allocator());
                  _M_deallocate(__new_start, __len);
                  __throw_exception_again;
                }
index 15adafc26718fef8c4ef69cb1bff2767facf0943..9e466378a62cc5dac6ca3cf99a2d1002dcc5ff13 100644 (file)
@@ -1,6 +1,6 @@
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -104,11 +104,11 @@ test04()
   std::vector<copycounter> a(10, c);
   copycounter::copycount = 0;
   a.insert(a.begin(), 20, c);
-  VERIFY(copycounter::copycount == 20 + 1);
+  VERIFY(copycounter::copycount == 20);
   a.insert(a.end(), 50, c);
-  VERIFY(copycounter::copycount == 70 + 2);
+  VERIFY(copycounter::copycount == 70);
   a.insert(a.begin() + 50, 100, c);
-  VERIFY(copycounter::copycount == 170 + 3);
+  VERIFY(copycounter::copycount == 170);
 }
 
 // Test vector::insert(iterator, count, value) makes no unneeded copies
index f4dbc19da416909f6221a835556ea6aa3638a33a..f24babc079286e44b8c6b5de6f812171445d0c79 100644 (file)
@@ -1,6 +1,6 @@
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -51,28 +51,28 @@ test01()
   a.resize(99);
   a.resize(100);
 #ifndef _GLIBCXX_DEBUG
-  VERIFY( copycounter::copycount == 100 + 4 );
+  VERIFY( copycounter::copycount == 100 + 1 );
 #else
-  VERIFY( copycounter::copycount == 100 + 4 + 4 );
+  VERIFY( copycounter::copycount == 100 + 1 + 4 );
 #endif
   a.resize(99);
   a.resize(0);
 #ifndef _GLIBCXX_DEBUG
-  VERIFY( copycounter::copycount == 100 + 4 );
+  VERIFY( copycounter::copycount == 100 + 1 );
 #else
-  VERIFY( copycounter::copycount == 100 + 4 + 6 );
+  VERIFY( copycounter::copycount == 100 + 1 + 6 );
 #endif
   a.resize(100);
 #ifndef _GLIBCXX_DEBUG  
-  VERIFY( copycounter::copycount == 200 + 5 );
+  VERIFY( copycounter::copycount == 200 + 2 );
 #else
-  VERIFY( copycounter::copycount == 200 + 5 + 7 );
+  VERIFY( copycounter::copycount == 200 + 2 + 7 );
 #endif
   a.clear();
 #ifndef _GLIBCXX_DEBUG
-  VERIFY( copycounter::copycount == 200 + 5 );
+  VERIFY( copycounter::copycount == 200 + 2 );
 #else
-  VERIFY( copycounter::copycount == 200 + 5 + 7 );
+  VERIFY( copycounter::copycount == 200 + 2 + 7 );
 #endif
 }