vector.swap and heap / stack

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steve Hill

    vector.swap and heap / stack

    Hi,
    suppose I have a vector allocated on the heap. Can I use a temporary
    (stack based vector) and swap to clear it, or is this unsafe. e.g.

    vector<int> *v;
    vector<int> tmp;
    v->swap(tmp); // is this an unsafe transfer between heap and stack
    // or does the allocator handle it safely?


    regards,
    steve
  • Ivan Vecerina

    #2
    Re: vector.swap and heap / stack

    "Steve Hill" <stephen.hill@m otorola.com> wrote in message
    news:c230c758.0 308200631.1c19b 673@posting.goo gle.com...
    | suppose I have a vector allocated on the heap. Can I use a temporary
    | (stack based vector) and swap to clear it, or is this unsafe. e.g.
    |
    | vector<int> *v;
    | vector<int> tmp;
    | v->swap(tmp); // is this an unsafe transfer between heap and stack
    | // or does the allocator handle it safely?

    It is safe.
    You could write:
    void clearV(vector<i nt>& c)
    { vector<int>().s wap(c); }

    And call it with various instances:

    auto_ptr<vector <int> > p = new vector<int>(4,5 );
    clearV( *p );

    vector<int> l(4,5);
    clearV( l );

    static vector<int> s(4,5);
    clearV( s );

    All is safe and sound...

    hth
    --



    Comment

    • Ivan Vecerina

      #3
      Re: vector.swap and heap / stack

      "Mike Wahler" <mkwahler@mkwah ler.net> wrote in message
      news:WIQ0b.1262 $lw4.1040@newsr ead3.news.pas.e arthlink.net...[color=blue]
      > Yes, this is safe. But note that you needn't define
      > 'tmp', you could use a temporary expression:
      >
      > v->swap(std::vect or<int>());[/color]

      This line is actually illegal in standard C++, unlike:
      std::vector<int >().swap(*v); // this is ok

      A temporary can only be bound to a *const* reference,
      while the parameter of swap is a non-const reference.
      (MSVC typically supports the line you posted as an
      extension of the language, but it is non-standard).
      [color=blue]
      > BTW, why not just use the 'clear()' member function:
      >
      > v->clear();[/color]

      Because clear does not free the memory allocated by *v,
      while using the swap trick typically will (although
      the standard does not formally guarantee this).


      Regards,
      Ivan
      --



      Comment

      • Ivan Vecerina

        #4
        Re: vector.swap and heap / stack

        "Mike Wahler" <mkwahler@mkwah ler.net> wrote in message
        news:Y2T0b.1396 $lw4.833@newsre ad3.news.pas.ea rthlink.net...[color=blue][color=green][color=darkred]
        > > > v->swap(std::vect or<int>());[/color]
        > >
        > > This line is actually illegal in standard C++, unlike:
        > > std::vector<int >().swap(*v); // this is ok[/color]
        >
        > Actually, I didn't mean either one.
        >
        > I meant:
        >
        > std::swap(*v, std::vector<int >());[/color]

        Note that this illegal, for the same reason as the
        first example ( v->swap(std::vect or<int>()) ).
        std::vector<int >() is a temporary, and both of the swap
        calls you suggested expect a non-const reference as a
        first parameter.
        This is unlike the valid option:
        std::vector<int >().swap(*v); // this is ok
        Here swap is invoked as a member function of the
        temporary, which is legal ISO C++.
        [color=blue][color=green][color=darkred]
        > > > BTW, why not just use the 'clear()' member function:
        > > >
        > > > v->clear();[/color]
        > >
        > > Because clear does not free the memory allocated by *v,[/color]
        >
        > AFAIK, it *will* free the memory occupied by
        > its elements (assuming of course that if the
        > elements are UDT's which manage memory, they do so
        > correctly).[/color]

        The standard mandates that v.clear() is equivalent to
        calling v.erase( v.begin(), v.end() ) -- in 23.1.1.
        The erase function does not cause the vector's memory
        to be reallocated (or freed). Its effect is to (23.2.4.3)
        invalidate "all the iterators and references *after* the
        point of the erase". Which means that the iterator
        returned by v.begin() shall not be invalidated by the
        call to v.clear().
        Basically, clear() will set the *size* of a vector to 0,
        but will leave the *capacity* of the vector unchanged.
        The memory block that std::vector has allocated to
        store its contents will not be freed.
        [color=blue][color=green]
        > > while using the swap trick typically will (although
        > > the standard does not formally guarantee this).[/color]
        >
        > Can you elaborate, please?[/color]

        v1.swap(v2) will exchange the memory blocks that are
        associated with the two vectors. This is typically done
        by swapping the pointers stored within each vector.

        When using: std::vector<int >().swap(*v);
        std::vector<int >() typically does not allocate any
        memory (its capacity is zero). After the memory blocks
        are exchanged, v will receive the block of capacity 0,
        and the temporary owns the memory previously associated
        with v -- which will be released by the temporary's
        destructor.

        Well, I hope this is not too confused... it's getting
        late here.

        Sincerely,
        Ivan
        --



        Comment

        • Ivan Vecerina

          #5
          Re: vector.swap and heap / stack

          "tom_usenet " <tom_usenet@hot mail.com> wrote in message
          news:3f44ae5d.9 544609@news.eas ynet.co.uk...
          | On Thu, 21 Aug 2003 01:37:01 +0200, "Ivan Vecerina"
          | <ivecATmyrealbo xDOTcom> wrote:
          |
          | >The standard mandates that v.clear() is equivalent to
          | >calling v.erase( v.begin(), v.end() ) -- in 23.1.1.
          | >The erase function does not cause the vector's memory
          | >to be reallocated (or freed). Its effect is to (23.2.4.3)
          | >invalidate "all the iterators and references *after* the
          | >point of the erase". Which means that the iterator
          | >returned by v.begin() shall not be invalidated by the
          | >call to v.clear().
          |
          | It certainly shall! erase invalidates iterators to erased elements, as
          | well as iterators to elements after the erase.

          From my reading of the standard (see the *after* above),
          I believe that the following is legal code:

          void deleteOddValues (std::vector<in t>& v)
          {
          std::vector<int >::iterator scan = v.begin();
          while( scan != v.end() )
          if( *s % 2 ) v.erase(scan);
          else ++scan;
          }

          The iterator from which the erasing starts remains valid
          (although it must not be dereferenced if it now equals end()).

          By extension, the following should also be ok:
          std::vector<int >::iterator b = v.begin();
          v.clear();
          assert( b == v.end() && b == v.begin() );

          Therefore, v.clear() cannot free the memory occupied by
          the vector (the allocator's interface doesn't support
          in-place shrinking of allocated memory).
          And the std::vector<int >().swap(v) trick has its place...


          Kind regards,
          Ivan
          --





          Comment

          • tom_usenet

            #6
            Re: vector.swap and heap / stack

            On Fri, 22 Aug 2003 17:53:44 +0200, "Ivan Vecerina"
            <ivec@myrealbox .com> wrote:
            [color=blue]
            >| It certainly shall! erase invalidates iterators to erased elements, as
            >| well as iterators to elements after the erase.
            >
            >From my reading of the standard (see the *after* above),
            >I believe that the following is legal code:
            >
            > void deleteOddValues (std::vector<in t>& v)
            > {
            > std::vector<int >::iterator scan = v.begin();
            > while( scan != v.end() )
            > if( *s % 2 ) v.erase(scan);
            > else ++scan;
            > }
            >
            >The iterator from which the erasing starts remains valid
            >(although it must not be dereferenced if it now equals end()).
            >
            >By extension, the following should also be ok:
            > std::vector<int >::iterator b = v.begin();
            > v.clear();
            > assert( b == v.end() && b == v.begin() );
            >
            >Therefore, v.clear() cannot free the memory occupied by
            >the vector (the allocator's interface doesn't support
            >in-place shrinking of allocated memory).
            >And the std::vector<int >().swap(v) trick has its place...[/color]

            Apologies, you're correct according to the standard, if not according
            to my expectations (although they have now been updated).

            Tom

            Comment

            Working...