basic question about std::vector

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

    #1

    basic question about std::vector

    I am using std::vector in my program:

    func()
    {
    std::vector <CMyClass *> vpMyClass;
    vpMyClass.push_ back(new CMyClass());
    vpMyClass.push_ back(new CMyClass());
    vpMyClass.push_ back(new CMyClass());

    //???? Required ??????????????//
    delete vpMyClass[0];
    delete vpMyClass[1];
    delete vpMyClass[2];

    }

    or vector automatically delete all pointer when it is out of the scope?

  • Rennie deGraaf

    #2
    Re: basic question about std::vector

    kathy wrote:[color=blue]
    > I am using std::vector in my program:
    >
    > func()
    > {
    > std::vector <CMyClass *> vpMyClass;
    > vpMyClass.push_ back(new CMyClass());
    > vpMyClass.push_ back(new CMyClass());
    > vpMyClass.push_ back(new CMyClass());
    >
    > //???? Required ??????????????//
    > delete vpMyClass[0];
    > delete vpMyClass[1];
    > delete vpMyClass[2];
    >
    > }
    >
    > or vector automatically delete all pointer when it is out of the scope?
    >[/color]

    Vector just knows about the value that it's storing - a binary value of
    the size of memory addresses on your system. It doesn't know or care
    about what that value actually means. So, yes, if you store pointers to
    dynamically allocated memory in a vector, you are responsible for
    freeing the memory yourself.

    Another perspective: If vectors containing pointers somehow knew to free
    dynamically allocated objects before deleting the entries, then the
    following code would probably crash your system:

    func()
    {
    std::vector<cha r*> vec;
    vec.push_back(" a string");
    vec.push_back(n ew char[100]);
    vec.push_back(N ULL);
    }

    The second thing that I push is a pointer to dynamically-allocated
    memory that must be freed. The first, however, is a pointer to
    statically-allocated memory, and attempting to delete it would result in
    undefined behaviour. The third points to nothing at all, although I
    think that delete is supposed to handle null pointers.

    If you must store pointers to dynamically allocated memory in STL
    containers (and there are reasons to do so), then you really should
    write your own wrapper class that handles both allocations and deletions
    itself, to ensure that no pointers to non-dynamic memory get stored, and
    that everything is appropriately deleted. Also, if there's a chance of
    an exception being thrown in your code, make sure that exceptions can't
    result in memory leaks.

    Rennie deGraaf

    Comment

    • mlimber

      #3
      Re: basic question about std::vector

      Rennie deGraaf wrote:[color=blue]
      > kathy wrote:[color=green]
      > > I am using std::vector in my program:
      > >
      > > func()
      > > {
      > > std::vector <CMyClass *> vpMyClass;
      > > vpMyClass.push_ back(new CMyClass());
      > > vpMyClass.push_ back(new CMyClass());
      > > vpMyClass.push_ back(new CMyClass());
      > >
      > > //???? Required ??????????????//
      > > delete vpMyClass[0];
      > > delete vpMyClass[1];
      > > delete vpMyClass[2];
      > >
      > > }
      > >
      > > or vector automatically delete all pointer when it is out of the scope?
      > >[/color]
      >
      > Vector just knows about the value that it's storing - a binary value of
      > the size of memory addresses on your system. It doesn't know or care
      > about what that value actually means. So, yes, if you store pointers to
      > dynamically allocated memory in a vector, you are responsible for
      > freeing the memory yourself.[/color]
      [snip][color=blue]
      > If you must store pointers to dynamically allocated memory in STL
      > containers (and there are reasons to do so), then you really should
      > write your own wrapper class that handles both allocations and deletions
      > itself, to ensure that no pointers to non-dynamic memory get stored, and
      > that everything is appropriately deleted. Also, if there's a chance of
      > an exception being thrown in your code, make sure that exceptions can't
      > result in memory leaks.
      >
      > Rennie deGraaf[/color]

      Another option is to use a canned smart pointer instead of a raw
      pointer to wrap them. Consider boost::shared_p tr, which is also part of
      TR1, the proposed extensions to the standard library:



      The OP's code would then look like:

      #include <boost/shared_ptr.hpp>

      void func()
      {
      std::vector< boost::shared_p tr<CMyClass> > vpMyClass;
      vpMyClass.push_ back(new CMyClass());
      vpMyClass.push_ back(new CMyClass());
      vpMyClass.push_ back(new CMyClass());

      // No delete needed
      }


      Cheers! --M

      Comment

      • Ben Pope

        #4
        Re: basic question about std::vector

        kathy wrote:[color=blue]
        > I am using std::vector in my program:
        >
        > func()
        > {
        > std::vector <CMyClass *> vpMyClass;
        > vpMyClass.push_ back(new CMyClass());
        > vpMyClass.push_ back(new CMyClass());
        > vpMyClass.push_ back(new CMyClass());
        >
        > //???? Required ??????????????//
        > delete vpMyClass[0];
        > delete vpMyClass[1];
        > delete vpMyClass[2];
        >
        > }[/color]

        You need to do this since *you* used new, *you* must use delete.
        [color=blue]
        > or vector automatically delete all pointer when it is out of the scope?[/color]

        It frees the memory required for the pointer, but not the memory the
        pointer points to.

        There may be a problem though, consider:

        func() {
        std::vector <CMyClass *> vpMyClass;
        vpMyClass.push_ back(new CMyClass());

        // Do something that throws an exception

        // this statement not reached, memory leaked.
        delete vpMyClass[0];
        }

        An oft-used solution is to use boost::shared_p tr:

        #include <vector>
        #include <boost/shared_ptr.hpp>

        class CMyClass {};

        typedef boost::shared_p tr<CMyClass> spMyClass;

        void func() {
        std::vector <spMyClass> vpMyClass;
        vpMyClass.push_ back(spMyClass( new CMyClass()));

        // Do something that may throw an exception

        //don't need to worry about cleanup, shared_ptr does it.
        }

        int main() {
        func();
        }


        If you want the container to manage the lifetime, then you can take a
        look at boost pointer conatiners:


        This will allow your original syntax for adding to the vector:

        boost::ptr_vect or<CMyClass> vpMyClass;
        vpMyClass.push_ back(new CMyClass());


        Have fun!

        Ben Pope
        --
        I'm not just a number. To many, I'm known as a string...

        Comment

        • Jeff Lefebvre

          #5
          Re: basic question about std::vector

          A nice way to free the memory dynamically allocated in your vector is
          described in "Effective C++, second edition" from Meyers:

          struct DeleteObject
          {
          template<typena me T>
          void operator()(cons t T* ptr) const
          {
          delete ptr;
          ptr = 0L;
          }
          };

          void func()
          {
          std::vector <CMyClass *> vpMyClass;
          vpMyClass.push_ back(new CMyClass());
          vpMyClass.push_ back(new CMyClass());
          vpMyClass.push_ back(new CMyClass());

          for_each(vpMyCl ass.begin(), vpMyClass.end() , DeleteObject()) ;
          }

          It works for any type!

          Comment

          • Axter

            #6
            Re: basic question about std::vector

            Jeff Lefebvre wrote:[color=blue]
            > A nice way to free the memory dynamically allocated in your vector is
            > described in "Effective C++, second edition" from Meyers:
            >
            > struct DeleteObject
            > {
            > template<typena me T>
            > void operator()(cons t T* ptr) const
            > {
            > delete ptr;
            > ptr = 0L;
            > }
            > };
            >
            > void func()
            > {
            > std::vector <CMyClass *> vpMyClass;
            > vpMyClass.push_ back(new CMyClass());
            > vpMyClass.push_ back(new CMyClass());
            > vpMyClass.push_ back(new CMyClass());
            >
            > for_each(vpMyCl ass.begin(), vpMyClass.end() , DeleteObject()) ;
            > }
            >
            > It works for any type![/color]
            I recommend a DeleteObject class that will also Nullify the pointer.
            Example code:
            class DeleteObject
            {
            public:
            template<typena me T>
            bool operator()(T& ptr)
            {
            delete &*ptr;
            ptr = NULL;
            return true;
            }
            };

            Example usage:
            vpMyClass.erase (remove_if(vpMy Class.begin(),
            vpMyClass.end() ,DeleteObject() ), vpMyClass.end() );

            The above DeleteObject class will also work with any object, and using
            the above method would delete and remove the objects from the vector
            all in one line of code.

            Comment

            • Jim Langston

              #7
              Re: basic question about std::vector


              "Rennie deGraaf" <ca.ucalgary.cp sc@degraaf> wrote in message
              news:Dgyvf.2579 25$ki.244533@pd 7tw2no...[color=blue]
              > kathy wrote:[color=green]
              >> I am using std::vector in my program:
              >>
              >> func()
              >> {
              >> std::vector <CMyClass *> vpMyClass;
              >> vpMyClass.push_ back(new CMyClass());
              >> vpMyClass.push_ back(new CMyClass());
              >> vpMyClass.push_ back(new CMyClass());
              >>
              >> //???? Required ??????????????//
              >> delete vpMyClass[0];
              >> delete vpMyClass[1];
              >> delete vpMyClass[2];
              >>
              >> }
              >>
              >> or vector automatically delete all pointer when it is out of the scope?
              >>[/color]
              >
              > Vector just knows about the value that it's storing - a binary value of
              > the size of memory addresses on your system. It doesn't know or care
              > about what that value actually means. So, yes, if you store pointers to
              > dynamically allocated memory in a vector, you are responsible for
              > freeing the memory yourself.
              >
              > Another perspective: If vectors containing pointers somehow knew to free
              > dynamically allocated objects before deleting the entries, then the
              > following code would probably crash your system:
              >
              > func()
              > {
              > std::vector<cha r*> vec;
              > vec.push_back(" a string");
              > vec.push_back(n ew char[100]);
              > vec.push_back(N ULL);
              > }
              >
              > The second thing that I push is a pointer to dynamically-allocated
              > memory that must be freed. The first, however, is a pointer to
              > statically-allocated memory, and attempting to delete it would result in
              > undefined behaviour. The third points to nothing at all, although I
              > think that delete is supposed to handle null pointers.
              >
              > If you must store pointers to dynamically allocated memory in STL
              > containers (and there are reasons to do so), then you really should
              > write your own wrapper class that handles both allocations and deletions
              > itself, to ensure that no pointers to non-dynamic memory get stored, and
              > that everything is appropriately deleted. Also, if there's a chance of
              > an exception being thrown in your code, make sure that exceptions can't
              > result in memory leaks.
              >
              > Rennie deGraaf[/color]

              Please explain this wrapper class you are talking about that handles both
              allocations and deletions itself.

              I use a lot of vectors or maps of pointers in my program(s). What would
              this wrapper class do?

              Oh, I think I understand. Instead of storing the pointer to char just store
              the wrapper class.

              class MyWrapper
              {
              public:
              MyClass *MyObject;
              MyWrapper() { MyObject = new MyClass }
              ~MyWrapper() { delete MyObject; }
              };

              std::vector <MyWrapper> MyVector;

              Interesting. This is a good thought and I think I might implement this.
              Then I don't have to iterate and delete the objects of my vector when it
              goes out of scope/gets deleted itself.


              Comment

              • Rennie deGraaf

                #8
                Re: basic question about std::vector

                Jim Langston wrote:[color=blue]
                > "Rennie deGraaf" <ca.ucalgary.cp sc@degraaf> wrote in message
                > news:Dgyvf.2579 25$ki.244533@pd 7tw2no...
                >[color=green]
                >>kathy wrote:
                >>[color=darkred]
                >>>I am using std::vector in my program:
                >>>
                >>>func()
                >>>{
                >>>std::vecto r <CMyClass *> vpMyClass;
                >>>vpMyClass.pu sh_back(new CMyClass());
                >>>vpMyClass.pu sh_back(new CMyClass());
                >>>vpMyClass.pu sh_back(new CMyClass());
                >>>
                >>>//???? Required ??????????????//
                >>>delete vpMyClass[0];
                >>>delete vpMyClass[1];
                >>>delete vpMyClass[2];
                >>>
                >>>}
                >>>
                >>>or vector automatically delete all pointer when it is out of the scope?
                >>>[/color]
                >>
                >>Vector just knows about the value that it's storing - a binary value of
                >>the size of memory addresses on your system. It doesn't know or care
                >>about what that value actually means. So, yes, if you store pointers to
                >>dynamically allocated memory in a vector, you are responsible for
                >>freeing the memory yourself.
                >>
                >>Another perspective: If vectors containing pointers somehow knew to free
                >>dynamically allocated objects before deleting the entries, then the
                >>following code would probably crash your system:
                >>
                >> func()
                >> {
                >> std::vector<cha r*> vec;
                >> vec.push_back(" a string");
                >> vec.push_back(n ew char[100]);
                >> vec.push_back(N ULL);
                >> }
                >>
                >>The second thing that I push is a pointer to dynamically-allocated
                >>memory that must be freed. The first, however, is a pointer to
                >>statically-allocated memory, and attempting to delete it would result in
                >>undefined behaviour. The third points to nothing at all, although I
                >>think that delete is supposed to handle null pointers.
                >>
                >>If you must store pointers to dynamically allocated memory in STL
                >>containers (and there are reasons to do so), then you really should
                >>write your own wrapper class that handles both allocations and deletions
                >>itself, to ensure that no pointers to non-dynamic memory get stored, and
                >>that everything is appropriately deleted. Also, if there's a chance of
                >>an exception being thrown in your code, make sure that exceptions can't
                >>result in memory leaks.
                >>
                >>Rennie deGraaf[/color]
                >
                >
                > Please explain this wrapper class you are talking about that handles both
                > allocations and deletions itself.[/color]

                There's no easy way (using standard C++) to store objects of different
                types derived from the same base class in an STL container. One common
                work-around is to store pointers to the base class in the container. If
                you must do this, then I reccomend that you wrap your container in a
                class that makes copies of objects to insert, returns const references
                to objects, deletes everything properly in its destructor, and is very
                careful about exceptions. For instance, if I have the following classes:

                class Shape;
                class Circle : public Shape;
                class Square : public Shape;

                and you needed to store both Circles and Squares in the same
                std::vector, then you could do something like this:

                class ShapeVector {
                std::vector<Sha pe*> shapes;
                public:
                const Shape& getFirst() { return *(shapes[0]); }
                void add(Shape& shape) { shapes.push_bac k(new Shape(shape)); }
                ~ShapeVector() { for (int i=0; i<shapes.length (); i++) delete
                shape[i]; }

                This is incomplete and probably won't compile, but hopefully you get the
                idea. If it's possible for any of your methods that allocate or free
                resources to throw exceptions, make sure that nothing is left hanging
                when an exception is thrown.

                (For the record, there are apparently ways to solve the problem that I
                described without using pointers, by using classes from boost.)

                If you're storing objects by pointer because you can't afford the cost
                of the STL copying them all the time, you might still use a trick like
                this, as long as you can afford the cost of copying them once.

                An alternate approach, that may be better in some situations, would be
                to use some sort of smart pointer. This would work even if you can't
                afford to copy your objects at all, or they aren't copyable. If you're
                not trying to use polymorphism, and your objects are cheaply copyable,
                them I can't think of any good reason to store pointers to dynamic
                memory in a container.

                [color=blue]
                > I use a lot of vectors or maps of pointers in my program(s). What would
                > this wrapper class do?
                >
                > Oh, I think I understand. Instead of storing the pointer to char just store
                > the wrapper class.
                >
                > class MyWrapper
                > {
                > public:
                > MyClass *MyObject;
                > MyWrapper() { MyObject = new MyClass }
                > ~MyWrapper() { delete MyObject; }
                > };
                >
                > std::vector <MyWrapper> MyVector;
                >
                > Interesting. This is a good thought and I think I might implement this.
                > Then I don't have to iterate and delete the objects of my vector when it
                > goes out of scope/gets deleted itself.[/color]

                This would be a good approach for expensively copyable or uncopyable
                objects. Don't bother for cheaply copiable stuff - just store them
                directly.

                Rennie deGraaf

                Comment

                • Axter

                  #9
                  Re: basic question about std::vector

                  Ben Pope wrote:[color=blue]
                  > kathy wrote:[color=green]
                  > > I am using std::vector in my program:
                  > >
                  > > func()
                  > > {
                  > > std::vector <CMyClass *> vpMyClass;
                  > > vpMyClass.push_ back(new CMyClass());
                  > > vpMyClass.push_ back(new CMyClass());
                  > > vpMyClass.push_ back(new CMyClass());
                  > >
                  > > //???? Required ??????????????//
                  > > delete vpMyClass[0];
                  > > delete vpMyClass[1];
                  > > delete vpMyClass[2];
                  > >
                  > > }[/color]
                  >
                  > You need to do this since *you* used new, *you* must use delete.
                  >[color=green]
                  > > or vector automatically delete all pointer when it is out of the scope?[/color]
                  >
                  > It frees the memory required for the pointer, but not the memory the
                  > pointer points to.
                  >
                  > There may be a problem though, consider:
                  >
                  > func() {
                  > std::vector <CMyClass *> vpMyClass;
                  > vpMyClass.push_ back(new CMyClass());
                  >
                  > // Do something that throws an exception
                  >
                  > // this statement not reached, memory leaked.
                  > delete vpMyClass[0];
                  > }
                  >
                  > An oft-used solution is to use boost::shared_p tr:
                  >
                  > #include <vector>
                  > #include <boost/shared_ptr.hpp>
                  >
                  > class CMyClass {};
                  >
                  > typedef boost::shared_p tr<CMyClass> spMyClass;
                  >
                  > void func() {
                  > std::vector <spMyClass> vpMyClass;
                  > vpMyClass.push_ back(spMyClass( new CMyClass()));
                  >
                  > // Do something that may throw an exception
                  >
                  > //don't need to worry about cleanup, shared_ptr does it.
                  > }
                  >
                  > int main() {
                  > func();
                  > }
                  >
                  >
                  > If you want the container to manage the lifetime, then you can take a
                  > look at boost pointer conatiners:
                  > http://www.boost.org/libs/ptr_contai...tr_vector.html
                  >
                  > This will allow your original syntax for adding to the vector:
                  >
                  > boost::ptr_vect or<CMyClass> vpMyClass;
                  > vpMyClass.push_ back(new CMyClass());
                  >[/color]

                  For a more generic method, you can use cow_ptr and/or copy_ptr smart
                  pointers.



                  Both of the above smart pointers can be used without having to create a
                  clone function, where as the boost pointer containers require
                  additional clone function logic in order to use it.
                  Also, (IMO) the cow_ptr/copy_ptr smart pointers are better at catching
                  slicing then are the boost pointer containers.
                  Example usage:
                  vector<cow_ptr< CMyClass> > vpMyClass;
                  vpMyClass.push_ back(new CMyClass);

                  Comment

                  • Jim Langston

                    #10
                    Re: basic question about std::vector

                    "Rennie deGraaf" <ca.ucalgary.cp sc@degraaf> wrote in message
                    news:2KIvf.1472 36$2k.86845@pd7 tw1no...[color=blue]
                    > Jim Langston wrote:[color=green]
                    >> "Rennie deGraaf" <ca.ucalgary.cp sc@degraaf> wrote in message
                    >> news:Dgyvf.2579 25$ki.244533@pd 7tw2no...
                    >>[color=darkred]
                    >>>kathy wrote:
                    >>>
                    >>>>I am using std::vector in my program:
                    >>>>
                    >>>>func()
                    >>>>{
                    >>>>std::vect or <CMyClass *> vpMyClass;
                    >>>>vpMyClass.p ush_back(new CMyClass());
                    >>>>vpMyClass.p ush_back(new CMyClass());
                    >>>>vpMyClass.p ush_back(new CMyClass());
                    >>>>
                    >>>>//???? Required ??????????????//
                    >>>>delete vpMyClass[0];
                    >>>>delete vpMyClass[1];
                    >>>>delete vpMyClass[2];
                    >>>>
                    >>>>}
                    >>>>
                    >>>>or vector automatically delete all pointer when it is out of the scope?
                    >>>>
                    >>>
                    >>>Vector just knows about the value that it's storing - a binary value of
                    >>>the size of memory addresses on your system. It doesn't know or care
                    >>>about what that value actually means. So, yes, if you store pointers to
                    >>>dynamicall y allocated memory in a vector, you are responsible for
                    >>>freeing the memory yourself.
                    >>>
                    >>>Another perspective: If vectors containing pointers somehow knew to free
                    >>>dynamicall y allocated objects before deleting the entries, then the
                    >>>following code would probably crash your system:
                    >>>
                    >>> func()
                    >>> {
                    >>> std::vector<cha r*> vec;
                    >>> vec.push_back(" a string");
                    >>> vec.push_back(n ew char[100]);
                    >>> vec.push_back(N ULL);
                    >>> }
                    >>>
                    >>>The second thing that I push is a pointer to dynamically-allocated
                    >>>memory that must be freed. The first, however, is a pointer to
                    >>>statically-allocated memory, and attempting to delete it would result in
                    >>>undefined behaviour. The third points to nothing at all, although I
                    >>>think that delete is supposed to handle null pointers.
                    >>>
                    >>>If you must store pointers to dynamically allocated memory in STL
                    >>>containers (and there are reasons to do so), then you really should
                    >>>write your own wrapper class that handles both allocations and deletions
                    >>>itself, to ensure that no pointers to non-dynamic memory get stored, and
                    >>>that everything is appropriately deleted. Also, if there's a chance of
                    >>>an exception being thrown in your code, make sure that exceptions can't
                    >>>result in memory leaks.
                    >>>
                    >>>Rennie deGraaf[/color]
                    >>
                    >>
                    >> Please explain this wrapper class you are talking about that handles both
                    >> allocations and deletions itself.[/color]
                    >
                    > There's no easy way (using standard C++) to store objects of different
                    > types derived from the same base class in an STL container. One common
                    > work-around is to store pointers to the base class in the container. If
                    > you must do this, then I reccomend that you wrap your container in a
                    > class that makes copies of objects to insert, returns const references
                    > to objects, deletes everything properly in its destructor, and is very
                    > careful about exceptions. For instance, if I have the following classes:
                    >
                    > class Shape;
                    > class Circle : public Shape;
                    > class Square : public Shape;
                    >
                    > and you needed to store both Circles and Squares in the same
                    > std::vector, then you could do something like this:
                    >
                    > class ShapeVector {
                    > std::vector<Sha pe*> shapes;
                    > public:
                    > const Shape& getFirst() { return *(shapes[0]); }
                    > void add(Shape& shape) { shapes.push_bac k(new Shape(shape)); }
                    > ~ShapeVector() { for (int i=0; i<shapes.length (); i++) delete
                    > shape[i]; }
                    >
                    > This is incomplete and probably won't compile, but hopefully you get the
                    > idea. If it's possible for any of your methods that allocate or free
                    > resources to throw exceptions, make sure that nothing is left hanging
                    > when an exception is thrown.
                    >
                    > (For the record, there are apparently ways to solve the problem that I
                    > described without using pointers, by using classes from boost.)
                    >
                    > If you're storing objects by pointer because you can't afford the cost
                    > of the STL copying them all the time, you might still use a trick like
                    > this, as long as you can afford the cost of copying them once.
                    >
                    > An alternate approach, that may be better in some situations, would be
                    > to use some sort of smart pointer. This would work even if you can't
                    > afford to copy your objects at all, or they aren't copyable. If you're
                    > not trying to use polymorphism, and your objects are cheaply copyable,
                    > them I can't think of any good reason to store pointers to dynamic
                    > memory in a container.
                    >
                    >[color=green]
                    >> I use a lot of vectors or maps of pointers in my program(s). What would
                    >> this wrapper class do?
                    >>
                    >> Oh, I think I understand. Instead of storing the pointer to char just
                    >> store
                    >> the wrapper class.
                    >>
                    >> class MyWrapper
                    >> {
                    >> public:
                    >> MyClass *MyObject;
                    >> MyWrapper() { MyObject = new MyClass }
                    >> ~MyWrapper() { delete MyObject; }
                    >> };
                    >>
                    >> std::vector <MyWrapper> MyVector;
                    >>
                    >> Interesting. This is a good thought and I think I might implement this.
                    >> Then I don't have to iterate and delete the objects of my vector when it
                    >> goes out of scope/gets deleted itself.[/color]
                    >
                    > This would be a good approach for expensively copyable or uncopyable
                    > objects. Don't bother for cheaply copiable stuff - just store them
                    > directly.[/color]

                    Actually, I store vectors of pointers for 2 different reasons.
                    The first one is polymorphism.
                    The second one is becuase I'm using a header to a dll that has objects I
                    want to store that don't follow the rule of three and aren't copyable.
                    Hence I store the pointers.


                    Comment

                    Working...