Safe to swap through pointer to vector?

Discussion in 'C++' started by Marcus Kwok, Feb 9, 2007.

  1. Marcus Kwok

    Marcus Kwok Guest

    I am utilizing a std::vector<int>, but due to a platform-specific reason
    (Managed C++, but this is irrelevant), in order to include it as a
    member of a class, I have to work with a pointer to it. However, I can
    declare concrete std::vectors as local variables in functions.

    Therefore, I would like to know whether the following construct is safe,
    i.e., there is no memory leak or undefined behavior. The demonstration
    example doesn't need all the class boilerplate so I left that out.

    Specifically, is it safe to call vector::swap() through a pointer to a
    vector? As far as I can reason, it should be OK, and adding output
    statements shows that *pv has the correct values, but I want to confirm
    whether or not this is undefined behavior that just happens to work by
    coincidence.


    #include <vector>

    int main()
    {
    using std::vector;

    vector<int>* pv = new vector<int>; // This represents my class variable
    vector<int> v; // This represents the local variable

    for (int i = 0; i < 3; ++i) {
    v.push_back(i);
    }

    pv->swap(v); // <----- I would like to know if this is safe

    delete pv;
    }



    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Feb 9, 2007
    #1
    1. Advertising

  2. Marcus Kwok

    Noah Roberts Guest

    Marcus Kwok wrote:

    > #include <vector>
    >
    > int main()
    > {
    > using std::vector;
    >
    > vector<int>* pv = new vector<int>; // This represents my class variable
    > vector<int> v; // This represents the local variable
    >
    > for (int i = 0; i < 3; ++i) {
    > v.push_back(i);
    > }
    >
    > pv->swap(v); // <----- I would like to know if this is safe


    Yes, it is safe.
     
    Noah Roberts, Feb 9, 2007
    #2
    1. Advertising

  3. Marcus Kwok

    Kai-Uwe Bux Guest

    Marcus Kwok wrote:

    > I am utilizing a std::vector<int>, but due to a platform-specific reason
    > (Managed C++, but this is irrelevant), in order to include it as a
    > member of a class, I have to work with a pointer to it. However, I can
    > declare concrete std::vectors as local variables in functions.
    >
    > Therefore, I would like to know whether the following construct is safe,
    > i.e., there is no memory leak or undefined behavior. The demonstration
    > example doesn't need all the class boilerplate so I left that out.
    >
    > Specifically, is it safe to call vector::swap() through a pointer to a
    > vector? As far as I can reason, it should be OK, and adding output
    > statements shows that *pv has the correct values, but I want to confirm
    > whether or not this is undefined behavior that just happens to work by
    > coincidence.
    >
    >
    > #include <vector>
    >
    > int main()
    > {
    > using std::vector;
    >
    > vector<int>* pv = new vector<int>; // This represents my class
    > variable
    > vector<int> v; // This represents the local variable
    >
    > for (int i = 0; i < 3; ++i) {
    > v.push_back(i);
    > }
    >
    > pv->swap(v); // <----- I would like to know if this is safe
    >
    > delete pv;
    > }


    The swap is fine. However, there is an exception safety problem in your
    code: should the v.push_back(i) at some point throw, the pv pointee will
    not be deallocated during stack unwinding. You should consider try-catch or
    using a smart pointer instead of a raw pointer.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 9, 2007
    #3
  4. Marcus Kwok

    Marcus Kwok Guest

    Kai-Uwe Bux <> wrote:
    > Marcus Kwok wrote:
    >> #include <vector>
    >>
    >> int main()
    >> {
    >> using std::vector;
    >>
    >> vector<int>* pv = new vector<int>; // This represents my class
    >> variable
    >> vector<int> v; // This represents the local variable
    >>
    >> for (int i = 0; i < 3; ++i) {
    >> v.push_back(i);
    >> }
    >>
    >> pv->swap(v); // <----- I would like to know if this is safe
    >>
    >> delete pv;
    >> }

    >
    > The swap is fine. However, there is an exception safety problem in your
    > code: should the v.push_back(i) at some point throw, the pv pointee will
    > not be deallocated during stack unwinding. You should consider try-catch or
    > using a smart pointer instead of a raw pointer.


    Thanks (and thanks to Noah as well). In the real code, pv is a class
    member that is allocated in a constructor and deleted in a destructor.
    I elided that from this example in order to minimize the code, but your
    point is well taken.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Feb 10, 2007
    #4
  5. Marcus Kwok

    Kai-Uwe Bux Guest

    Marcus Kwok wrote:

    > Kai-Uwe Bux <> wrote:
    >> Marcus Kwok wrote:
    >>> #include <vector>
    >>>
    >>> int main()
    >>> {
    >>> using std::vector;
    >>>
    >>> vector<int>* pv = new vector<int>; // This represents my class
    >>> variable
    >>> vector<int> v; // This represents the local variable
    >>>
    >>> for (int i = 0; i < 3; ++i) {
    >>> v.push_back(i);
    >>> }
    >>>
    >>> pv->swap(v); // <----- I would like to know if this is safe
    >>>
    >>> delete pv;
    >>> }

    >>
    >> The swap is fine. However, there is an exception safety problem in your
    >> code: should the v.push_back(i) at some point throw, the pv pointee will
    >> not be deallocated during stack unwinding. You should consider try-catch
    >> or using a smart pointer instead of a raw pointer.

    >
    > Thanks (and thanks to Noah as well). In the real code, pv is a class
    > member that is allocated in a constructor and deleted in a destructor.


    That sure is good. By and in itself, however, it does not eliminate the
    problem. Probably, I am not going to tell you anything you don't know, but
    since it somehow illustrates the trickyness of getting pointers exception
    safe, I will say it anyway. Consider:

    class X {

    vector<int>* pv;

    public:

    ~X ( void ) {
    delete pv;
    }

    X ( void )
    : pv ( new vector<int> () );
    {}

    // so far everything is fine. But:

    X ( some_type some_data )
    : pv ( new vector<int> () )
    {
    // populate pv:
    // if this throws, our destructor will not be called !!!
    }

    };

    Therefore, constructors that initialize pointees have to take care of
    cleaning up their own allocation mess.

    Also, as soon as you have two pointer members in you class, allocation of
    the second may throw and cause the first to leak. Pointers are just a pain.


    > I elided that from this example in order to minimize the code, but your
    > point is well taken.



    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 10, 2007
    #5
  6. Kai-Uwe Bux wrote:
    > Marcus Kwok wrote:
    >
    >> Kai-Uwe Bux <> wrote:
    >>> Marcus Kwok wrote:
    >>>> #include <vector>
    >>>>
    >>>> int main()
    >>>> {
    >>>> using std::vector;
    >>>>
    >>>> vector<int>* pv = new vector<int>; // This represents my class
    >>>> variable
    >>>> vector<int> v; // This represents the local variable
    >>>>
    >>>> for (int i = 0; i < 3; ++i) {
    >>>> v.push_back(i);
    >>>> }
    >>>>
    >>>> pv->swap(v); // <----- I would like to know if this is safe
    >>>>
    >>>> delete pv;
    >>>> }
    >>> The swap is fine. However, there is an exception safety problem in your
    >>> code: should the v.push_back(i) at some point throw, the pv pointee will
    >>> not be deallocated during stack unwinding. You should consider try-catch
    >>> or using a smart pointer instead of a raw pointer.

    >> Thanks (and thanks to Noah as well). In the real code, pv is a class
    >> member that is allocated in a constructor and deleted in a destructor.

    >
    > That sure is good. By and in itself, however, it does not eliminate the
    > problem. Probably, I am not going to tell you anything you don't know, but
    > since it somehow illustrates the trickyness of getting pointers exception
    > safe, I will say it anyway. Consider:
    >
    > class X {
    >
    > vector<int>* pv;
    >
    > public:
    >
    > ~X ( void ) {
    > delete pv;
    > }
    >
    > X ( void )
    > : pv ( new vector<int> () );
    > {}
    >
    > // so far everything is fine. But:
    >
    > X ( some_type some_data )
    > : pv ( new vector<int> () )
    > {
    > // populate pv:
    > // if this throws, our destructor will not be called !!!
    > }
    >
    > };
    >
    > Therefore, constructors that initialize pointees have to take care of
    > cleaning up their own allocation mess.


    auto_ptr to the rescue:


    class X {

    auto_ptr<vector<int> > pv;

    public:
    //No need for a destructor

    X ( void )
    : pv ( new vector<int> () )
    {}

    X ( some_type some_data )
    : pv ( new vector<int> () )
    {
    // populate pv:
    // if this throws, pv's destructor *will* called
    }
    };


    --
    Clark S. Cox III
     
    Clark S. Cox III, Feb 10, 2007
    #6
  7. Marcus Kwok

    Marcus Kwok Guest

    Kai-Uwe Bux <> wrote:
    > That sure is good. By and in itself, however, it does not eliminate the
    > problem. Probably, I am not going to tell you anything you don't know, but
    > since it somehow illustrates the trickyness of getting pointers exception
    > safe, I will say it anyway. Consider:
    >
    > class X {
    >
    > vector<int>* pv;
    >
    > public:
    >
    > ~X ( void ) {
    > delete pv;
    > }
    >
    > X ( void )
    > : pv ( new vector<int> () );
    > {}
    >
    > // so far everything is fine. But:
    >
    > X ( some_type some_data )
    > : pv ( new vector<int> () )
    > {
    > // populate pv:
    > // if this throws, our destructor will not be called !!!
    > }
    >
    > };
    >
    > Therefore, constructors that initialize pointees have to take care of
    > cleaning up their own allocation mess.


    True. In my specific case, it is being used in the implementation of a
    GUI window which will not be copyable.

    > Also, as soon as you have two pointer members in you class, allocation of
    > the second may throw and cause the first to leak. Pointers are just a pain.


    Yes, I found that these articles helped illuminate for me many of the
    intricacies of pointer usage:

    (mind the long URIs):
    http://icu.sourceforge.net/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

    and the update to the article:
    http://icu.sourceforge.net/docs/papers/cpp_report/the_assignment_operator_revisited.html

    Of course, if I had my way, I wouldn't use pointers in this case either,
    but I am forced to due to the constraints of the framework (.NET) that
    the GUI must be implemented in.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Feb 13, 2007
    #7
  8. Marcus Kwok

    Marcus Kwok Guest

    Clark S. Cox III <> wrote:
    > Kai-Uwe Bux wrote:
    >> Therefore, constructors that initialize pointees have to take care of
    >> cleaning up their own allocation mess.

    >
    > auto_ptr to the rescue:
    >
    >
    > class X {
    >
    > auto_ptr<vector<int> > pv;
    >
    > public:
    > //No need for a destructor
    >
    > X ( void )
    > : pv ( new vector<int> () )
    > {}
    >
    > X ( some_type some_data )
    > : pv ( new vector<int> () )
    > {
    > // populate pv:
    > // if this throws, pv's destructor *will* called
    > }
    > };


    Yes, a similar technique is used in the articles I linked to in another
    post, though in the context of writing an assignment operator.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Feb 13, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Black
    Replies:
    3
    Views:
    440
    Victor Bazarov
    Jul 2, 2004
  2. Jason Heyes
    Replies:
    8
    Views:
    755
    Andrew Koenig
    Jan 15, 2006
  3. Replies:
    8
    Views:
    1,989
    Csaba
    Feb 18, 2006
  4. Niels Dekker (no reply address)

    What swap is called when using std::swap?

    Niels Dekker (no reply address), Jul 19, 2006, in forum: C++
    Replies:
    4
    Views:
    1,007
    Niels Dekker (no reply address)
    Jul 20, 2006
  5. George2
    Replies:
    4
    Views:
    398
    dizzy
    Jan 8, 2008
Loading...

Share This Page