Safe to swap through pointer to vector?

M

Marcus Kwok

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;
}
 
N

Noah Roberts

Marcus said:
#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.
 
K

Kai-Uwe Bux

Marcus said:
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
 
M

Marcus Kwok

Kai-Uwe Bux said:
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.
 
K

Kai-Uwe Bux

Marcus said:
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
 
C

Clark S. Cox III

Kai-Uwe Bux said:
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
}
};
 
M

Marcus Kwok

Kai-Uwe Bux said:
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.
 
M

Marcus Kwok

Clark S. Cox III said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top