can I use stl vector iterator to delete a vector of pointers?

J

James Kanze

As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion. Practically, of course, there
won't be any problems, even on architectures where the lvalue to
rvalue conversion can cause problems.
 
J

James Kanze

Vladimir Jovic <[email protected]>, on 03/09/2010 12:01:45, wrote:

[...]
Ah, I understand now. Yes, raw pointers are dangerous, but are
sometimes a necessary evil, paraphrasing the C++ FAQ.

This is a widespread myth. Globally, raw pointers are probably
less dangerous than std::shared_ptr; at least, the object
doesn't get deleted unless you explicitly ask for it. Other
shared pointers fare better, but in any reasonable application,
most pointers are used for navigation, and there's absolutely no
reason to use a smart pointer for that.
 
K

Kai-Uwe Bux

Francesco said:
Seungbeom Kim<[email protected]>, on 06/09/2010 01:50:09, wrote:
So, do we really need to set the pointers to null before destroying
the vector?
As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So to be formally fine I need something like this...

vector<sometype*> vec;
vec.push_back(new sometype);
sometype* ptr = vec[0];
vec[0] = 0;
delete ptr;

...or variations thereof. Thank you for the correction.

Well, that is a somewhat contested issue. More importantly, though, it is
based upon an interpretation of language that is subject to heavy changes in
C++0x. My preliminary understanding of is that a contorted work-around like
the above is not necessary under the C++0x rules.

And you say that because you're confident that most decent
implementations out there will not perform the conversion during the
element assignment - otherwise, your mention about program crashes,
else-thread, would conflict with this statement.

An implementation would have to be deliberately mean and waste resources on
being mean to trigger lvalue-rvalue conversions for no reason.


Best

Kai-Uwe Bux
 
F

Francesco S. Carta

Francesco said:
So, do we really need to set the pointers to null before destroying
the vector?

As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So to be formally fine I need something like this...

vector<sometype*> vec;
vec.push_back(new sometype);
sometype* ptr = vec[0];
vec[0] = 0;
delete ptr;

...or variations thereof. Thank you for the correction.

Well, that is a somewhat contested issue. More importantly, though, it is
based upon an interpretation of language that is subject to heavy changes in
C++0x. My preliminary understanding of is that a contorted work-around like
the above is not necessary under the C++0x rules.

For your very words, it has to be proved formally necessary even in
C++03, for that matter.
An implementation would have to be deliberately mean and waste resources on
being mean to trigger lvalue-rvalue conversions for no reason.

Uhm... the standard does not forbid implementations to be mean, does it?
ehehehehe ;-)

Kidding apart, I'm just interested in the process of clarifying dark
corners of the standard, in these very posts, and about this, I'd like
to read some elaboration on your first sentence above.

If I understand you correctly, your reading of the standard does not
allow a std::vector implementation to perform lvalue to rvalue
conversions during element assignment, is that what you meant?
 
K

Kai-Uwe Bux

Francesco said:
Francesco said:
So, do we really need to set the pointers to null before destroying
the vector?

As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So to be formally fine I need something like this...

vector<sometype*> vec;
vec.push_back(new sometype);
sometype* ptr = vec[0];
vec[0] = 0;
delete ptr;

...or variations thereof. Thank you for the correction.

Well, that is a somewhat contested issue. More importantly, though, it is
based upon an interpretation of language that is subject to heavy changes
in C++0x. My preliminary understanding of is that a contorted work-around
like the above is not necessary under the C++0x rules.

For your very words, it has to be proved formally necessary even in
C++03, for that matter.

Ok, for C++0x some of the issues for interpreting the standard are:

a) How does 4.1/1 imply that lvalue-rvalue conversion of invalid pointers is
UB? The wording is:

If the object to which the lvalue refers is not an object of type T and is
not an object of a type derived from T, or if the object is uninitialized,
a program that necessitates this conversion has undefined behavior.

Code example:

int* p = new int();
delete p;
int* q = p; // lvalue-rvalue conversion

So, in this example, is the object to which p refers not of type int*? or is
the the object analogous to an uninitialized object?

Assuming the first alternative, we find that

std::vector< int* > v;
v.push_back( new int () );
delete v.back();

creates a vector whose elements are not objects of type int*. In fact, it
would be hard to say what the type of the stored object is. In particular,
is the type of the object in the vector CopyConstructible?


b) How to precisely interpret CopyConstructibility (table 30). E.g.,

int* p = new int();
delete p;
// is int* CopyConstructible at this point?

If one would arge a strong NO here, we arrive at _very_ unwelcome
consequences:

std::vector<int*> v;
v.push_back( new int () );
int* p = new int ();
delete p;
std::vector<int*> w ( v );

The last line would be UB if int* was not CopyConstructible. :)


Note: I don't wand to suggest how to resolve these issues of interpretation.

Uhm... the standard does not forbid implementations to be mean, does it?
ehehehehe ;-)

No, it does not :)

Kidding apart, I'm just interested in the process of clarifying dark
corners of the standard, in these very posts, and about this, I'd like
to read some elaboration on your first sentence above.

If I understand you correctly, your reading of the standard does not
allow a std::vector implementation to perform lvalue to rvalue
conversions during element assignment, is that what you meant?

No, that's not what I mean. Consider:

reference operator[] ( size_type n ) {
value_type dummy ( the_data[n] );
return ( the_data[n] );
}

I don't see any language in the standard that would render the above a non-
conforming implementation.

What I mean is: no sane implementation does that.


Best

Kai-Uwe Bux
 
S

Seungbeom Kim

As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So, that means { delete a; } is fine just before destroying an array
a, but for vectors even { delete v; v = 0; } is insufficient,
and we should do { T* p = v; v = 0; delete p; } ...?

Isn't this an unnecessary burden for the users of vector? Isn't it
against the C++ design rule "Provide as good support for user-defined
types as for built-in types."?
(It is already a difficult task to make people convinced that it is UB
just to read the value of, not to dereference, an invalid pointer. Sigh.)
Practically, of course, there
won't be any problems, even on architectures where the lvalue to
rvalue conversion can cause problems.

So I'm wondering; if some extra steps have to be done just to avoid
invoking UB formally but not doing so will cause no problems on any
real implementations in practice, then why not let the standard reflect
the reality and make it officially acceptable not to do the extra steps?
I.e. by specifying that an element access for a vector as an lvalue
shouldn't cause an lvalue-to-rvalue conversion, and that neither should
the destruction of the vector.
 
A

Alf P. Steinbach /Usenet

* Seungbeom Kim, on 07.09.2010 05:23:
Seungbeom Kim<[email protected]>, on 06/09/2010 01:50:09, wrote:
So, do we really need to set the pointers to null before destroying
the vector?
As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So, that means { delete a; } is fine just before destroying an array
a, but for vectors even { delete v; v = 0; } is insufficient,
and we should do { T* p = v; v = 0; delete p; } ...?

Isn't this an unnecessary burden for the users of vector? Isn't it
against the C++ design rule "Provide as good support for user-defined
types as for built-in types."?
(It is already a difficult task to make people convinced that it is UB
just to read the value of, not to dereference, an invalid pointer. Sigh.)
Practically, of course, there
won't be any problems, even on architectures where the lvalue to
rvalue conversion can cause problems.

So I'm wondering; if some extra steps have to be done just to avoid
invoking UB formally but not doing so will cause no problems on any
real implementations in practice, then why not let the standard reflect
the reality and make it officially acceptable not to do the extra steps?
I.e. by specifying that an element access for a vector as an lvalue
shouldn't cause an lvalue-to-rvalue conversion, and that neither should
the destruction of the vector.


I think that would work. :)

At first millisecond I thought the last requirement would be problematic as
stated, but destruction of an object of class type doesn't involve lvalue to rvalue?

Disclaimer: just out of bed and no coffee yet.


Cheers,

- Alf
 
F

Francesco S. Carta

Francesco said:
Francesco S. Carta wrote:



So, do we really need to set the pointers to null before destroying
the vector?

As it seems, formally, yes [*], we need to nullify them,
because the actions performed by the vector during
reallocation or during destruction might lead to that lvalue
to rvalue conversion, thus calling UB into play.

Formally, you need to nullify the pointer in the vector before
deleting it, since nullifying it (assigning NULL to it) involves
accessing into the vector, which could theoretically lead to an
lvalue to rvalue conversion.

So to be formally fine I need something like this...

vector<sometype*> vec;
vec.push_back(new sometype);
sometype* ptr = vec[0];
vec[0] = 0;
delete ptr;

...or variations thereof. Thank you for the correction.

Well, that is a somewhat contested issue. More importantly, though, it is
based upon an interpretation of language that is subject to heavy changes
in C++0x. My preliminary understanding of is that a contorted work-around
like the above is not necessary under the C++0x rules.

For your very words, it has to be proved formally necessary even in
C++03, for that matter.

Ok, for C++0x some of the issues for interpreting the standard are:

a) How does 4.1/1 imply that lvalue-rvalue conversion of invalid pointers is
UB? The wording is:

If the object to which the lvalue refers is not an object of type T and is
not an object of a type derived from T, or if the object is uninitialized,
a program that necessitates this conversion has undefined behavior.

Code example:

int* p = new int();
delete p;
int* q = p; // lvalue-rvalue conversion

So, in this example, is the object to which p refers not of type int*? or is
the the object analogous to an uninitialized object?

Assuming the first alternative, we find that

std::vector< int*> v;
v.push_back( new int () );
delete v.back();

creates a vector whose elements are not objects of type int*. In fact, it
would be hard to say what the type of the stored object is. In particular,
is the type of the object in the vector CopyConstructible?


b) How to precisely interpret CopyConstructibility (table 30). E.g.,

int* p = new int();
delete p;
// is int* CopyConstructible at this point?

If one would arge a strong NO here, we arrive at _very_ unwelcome
consequences:

std::vector<int*> v;
v.push_back( new int () );
int* p = new int ();
delete p;
std::vector<int*> w ( v );

The last line would be UB if int* was not CopyConstructible. :)


Note: I don't wand to suggest how to resolve these issues of interpretation.

Uh... we have quite some unresolved interpretation issues with the
current standard, I was somehow hoping that some of those issues were
going to be dissipated in the upcoming one...
Uhm... the standard does not forbid implementations to be mean, does it?
ehehehehe ;-)

No, it does not :)

Kidding apart, I'm just interested in the process of clarifying dark
corners of the standard, in these very posts, and about this, I'd like
to read some elaboration on your first sentence above.

If I understand you correctly, your reading of the standard does not
allow a std::vector implementation to perform lvalue to rvalue
conversions during element assignment, is that what you meant?

No, that's not what I mean. Consider:

reference operator[] ( size_type n ) {
value_type dummy ( the_data[n] );
return ( the_data[n] );
}

I don't see any language in the standard that would render the above a non-
conforming implementation.

What I mean is: no sane implementation does that.

Ah, but as you put it in first place, it seemed that you were speaking
about the formal interpretation under C++03.

All right, as far as I can tell, the weird and contorted work-around is
still necessary to formally avoid any potential UB under the current
standard.

At the practical stage, I will happily send to death any vector of
dangling pointers without many worries ;-)
 

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,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top