Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::vector: Surprising order of destruction!

430 views
Skip to first unread message

PiotrN

unread,
May 31, 2012, 12:20:25 AM5/31/12
to
Hello,

I am curious is there any C++ standard rules about destruction of
std::vector elements. For arrays it applies “reverse order” rule –
order of destruction is reverse to elements construction – and it is
in reverse order of indexes.
It seems, that, for at least one compiler which I tested, the order of
destruction in std::vector is in natural order of indexes, which is
very strange to me!

Consider this simple example which failed for std::vector – whilst
working fine for arrays:
struct T {
T(int i, T* n = 0) : i(i), n(n) { cout << *this << endl; }
T(const T& o) : i(o.i), n(o.n) { cout << *this << " from " << o <<
endl; }
~T() { cout << "~" << *this << endl; }
int i;
T* n;
friend ostream& operator << (ostream& os, const T& t) {
os << "T(" << t.i;
if (t.n) os << "," << *t.n;
return os << ")";
}
};

1) ARRAY
int main() {
T a[] = { 1, 2, T(3, &a[0]) };
cout << "main() ended" << endl;
}
OUTPUT:
T(1)
T(2)
T(3,T(1))
main() ended
~T(3,T(1))
~T(2)
~T(1)

2) VECTOR - surprising order of destruction!
int main() {
vector<T> v;
v.reserve(3);
v.push_back(1);
v.push_back(2);
v.push_back(T(3, &v[0]); */ // that will crash in destruction!!!
}
OUTPUT:
T(1)
T(1) from T(1)
~T(1)
T(2)
T(2) from T(2)
~T(2)
T(3,T(1))
T(3,T(1)) from T(3,T(1))
~T(3,T(1))
main() ended
~T(1)
~T(2)
~T(3,
Segmentation fault

Thanks,
Piotr Nycz


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
May 31, 2012, 3:15:37 PM5/31/12
to
On 2012-05-31 06:20, PiotrN wrote:
> I am curious is there any C++ standard rules about destruction of
> std::vector elements.

The standard does not specify the order of destruction of the elements.
Neither does it do so for clear(), resize(), and other member functions
that would destroy any element.

> For arrays it applies “reverse order” rule –
> order of destruction is reverse to elements construction – and it is
> in reverse order of indexes.

Well yes, and this is also guaranteed for array-delete expressions.
Nonetheless I think there is a significant difference here: The types
with guaranteed destruction order are fixed-size types, but std::vector
and most other containers have runtime-sizes.

> It seems, that, for at least one compiler which I tested, the order of
> destruction in std::vector is in natural order of indexes,

Actually I think this is what I also would expect, because it is usually
the most direct way to implement the specification.

> which is
> very strange to me!
>
> Consider this simple example which failed for std::vector – whilst
> working fine for arrays:
> struct T {
> T(int i, T* n = 0) : i(i), n(n) { cout<< *this<< endl; }
> T(const T& o) : i(o.i), n(o.n) { cout<< *this<< " from "<< o<<
> endl; }
> ~T() { cout<< "~"<< *this<< endl; }
> int i;
> T* n;
> friend ostream& operator<< (ostream& os, const T& t) {
> os<< "T("<< t.i;
> if (t.n) os<< ","<< *t.n;
> return os<< ")";
> }
> };
>
> 1) ARRAY
> int main() {
> T a[] = { 1, 2, T(3,&a[0]) };
> cout<< "main() ended"<< endl;
> }
> OUTPUT:
> T(1)
> T(2)
> T(3,T(1))
> main() ended
> ~T(3,T(1))
> ~T(2)
> ~T(1)

Yes, this is required.

> 2) VECTOR - surprising order of destruction!
> int main() {
> vector<T> v;
> v.reserve(3);
> v.push_back(1);
> v.push_back(2);
> v.push_back(T(3,&v[0]); */ // that will crash in destruction!!!
> }

Yes, presumably.

The question is whether this is really a defect or not. Personally I
have not stumbled across this limitation in real-world projects. But if
you want a normative change, I don't think that specifying the order in
the destructor alone is sufficient. Presumably wording is needed in a
lot of other functions that may destroy elements of the vector. I'm not
convinced that the result is worth the effort behind that. I guess it
will break most if not all existing implementations of std::vector.

HTH & Greetings from Bremen,

Daniel Krügler

Francis Glassborow

unread,
May 31, 2012, 3:25:29 PM5/31/12
to
On 31/05/2012 05:20, PiotrN wrote:
> Hello,
>
> I am curious is there any C++ standard rules about destruction of
> std::vector elements. For arrays it applies “reverse order” rule –
> order of destruction is reverse to elements construction – and it is
> in reverse order of indexes.
> It seems, that, for at least one compiler which I tested, the order of
> destruction in std::vector is in natural order of indexes, which is
> very strange to me!
>

The elements of an array are in a fixed order (though it is possible to
move them around by , for example, using a swap function. More
importantly, they are also in a fixed location and it takes a deliberate
(hopefully conscious) action of the programmer to relocate either the
whole array or shuffle the members, As a general rule it is safe to
destroy the elements in reverse order of construction. However, note
that if the programmer does use a swap() function or similar on elements
of an array that reference each other then undefined behaviour is quite
probable.

In the case of a vector, the design anticipates reordering and growth
(and your vector would become unstable simply through growth because the
first element would move when growth required relocation of the whole
vector). Indeed any vector that includes such internal references is an
accident waiting to happen.

Against that background it seems unreasonable to require that a vector
keeps track of the order of construction of its members (that could get
quite complex and impose an overhead on the management of every vector).
If we are not going to track the order of construction there seems no
reason to require destruction in any particular order. ISTM that
destructing in index order is just as reasonable as destructing in
reverse index order as neither would normally be in reverse order of
construction.

Christopher Dearlove

unread,
May 31, 2012, 3:33:20 PM5/31/12
to
On May 31, 5:20 am, PiotrN <piotr...@gmail.com> wrote:
> It seems, that, for at least one compiler which I tested, the order of
> destruction in std::vector is in natural order of indexes, which is
> very strange to me!

I've snipped your example use push_back. But suppose you'd instead
inserted at the front, then (and the necessary copying of the existing
objects doesn't affect this) the newest object would be at the front.
And if you'd inserted randomly?

It's neither practical nor desirable for a vector to recall what order
its elements were inserted in and destroy accordingly.

red floyd

unread,
May 31, 2012, 7:05:29 PM5/31/12
to
On 5/30/2012 9:20 PM, PiotrN wrote:
> Hello,
>
> I am curious is there any C++ standard rules about destruction of
> std::vector elements. For arrays it applies “reverse order” rule –
> order of destruction is reverse to elements construction – and it is
> in reverse order of indexes.
> It seems, that, for at least one compiler which I tested, the order of
> destruction in std::vector is in natural order of indexes, which is
> very strange to me!
>

Oddly enough, I couldn't find anything in ISO 14882:2003 that specifies
the destruction order of vector elements (I looked at all of Chapter
23). I may have missed something, or it may just be implementation
defined, or unspecified (as opposed to undefined) behavior.

Did they tighten this up in C++11?

PiotrN

unread,
May 31, 2012, 7:06:16 PM5/31/12
to
On 31 Maj, 21:15, Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:
> On 2012-05-31 06:20, PiotrN wrote:
>
> > I am curious is there any C++ standard rules about destruction of
> > std::vector elements.
>
> The standard does not specify the order of destruction of the elements.
> Neither does it do so for clear(), resize(), and other member functions
> that would destroy any element.
>
> > It seems, that, for at least one compiler which I tested, the order of
> > destruction in std::vector is in natural order of indexes,
>
> Actually I think this is what I also would expect, because it is usually
> the most direct way to implement the specification.
>

Daniel,

But why destruction in natural order is natural way of implementing
the specification?
I strongly believe that in case of vector<> there is no PERFORMANCE
difference between both directions and reverse order of destruction is
so natural for C++ that I am personally very surprised that is was not
selected by compilar vendors. I tested so far a couple of compilers
and all was implemented in surprised to me way.
I undestand that standard says nothing about it, the container is
resizable, elements can be switched - but these are neutral arguments
- they are not pro or againt any of destruction order.
Then why not choose reverse order?

Best Regards,
Piotr Nycz

James K. Lowden

unread,
Jun 1, 2012, 3:28:28 AM6/1/12
to
On Thu, 31 May 2012 12:25:29 -0700 (PDT)
Francis Glassborow <francis.g...@btinternet.com> wrote:

> As a general rule it is safe to destroy the elements in reverse order
> of construction. However, note that if the programmer does use a swap
> () function or similar on elements of an array that reference each
> other then undefined behaviour is quite probable.

As a general rule, it is safe to destroy elements in any order at all.
We know that because that's what's been happening for decades.

No std container records the order of construction. Efforts to infer
that order -- say, because vector elements were constructed
sequentially -- would fail in the general case.

swap() is only one example. Assignment is another; any element in a
non-const collection can be overwritten by something else. That other
thing might have been constructed anytime, even before or after the
collection itself. In a collection of pointers, the pointed-to objects
could be assigned to.

--jkl

Dave Harris

unread,
Jun 2, 2012, 8:53:02 AM6/2/12
to
{ Reformatted; please limit your lines to 70 characters -mod }

francis.g...@btinternet.com (Francis Glassborow) wrote
(abridged):
> Against that background it seems unreasonable to require that a
> vector keeps track of the order of construction of its members (that
> could get quite complex and impose an overhead on the management of
> every vector). If we are not going to track the order of
> construction there seems no reason to require destruction in any
> particular order. ISTM that destructing in index order is just as
> reasonable as destructing in reverse index order as neither would
> normally be in reverse order of construction.

I agree with the first part, but not with the second. Apart from
anything else, allowing forward order violates the principle of least
surprise. If I have an array of objects, and I replace it with a
vector of objects, I just wouldn't expect the order of construction
and destruction to change. So far as I can tell, there's no reason for
it to.

Destruction order can be important whenever the destructors have side
effects, even if they don't directly refer to other objects in the
same collection. For example, an object might register itself with
some singly-linked list in its constructor and unregister itself in
its destructor. Then destruction in reverse order would avoid the need
to traverse the linked list, turning an O(n*n) operation into an O(n)
one.

I agree that in complex cases where the user uses insert() or swap(),
this won't hold, but for me these cases are not "normal". Most of my
vectors are grown only from the end (or not at all). If I wanted to
rely on destruction order, I could probably ensure that reverse index
order was what I needed. If not, then I'm no worse off than I am now.

It seems to me leaving destruction order implementation defined, is
giving the implementation a freedom that it doesn't need, while taking
away a guarantee that users sometimes do need.

Daniel Krügler mentions that changing the order would break most
existing implementations. Unless someone can show a reason that
implementations do need the freedom, I suspect that's the real reason:
early vector implementations got it wrong, and now it's too late to
change.

-- Dave Harris, Nottingham, UK.

Christopher Dearlove

unread,
Jun 6, 2012, 8:02:06 PM6/6/12
to
On Jun 2, 1:53 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
> It seems to me leaving destruction order implementation defined, is
> giving the implementation a freedom that it doesn't need, while taking
> away a guarantee that users sometimes do need.

I don't see any sensible user needing that guarantee, even if it
weren't for all the examples that show problems. The original code was
well-designed as a demonstration of the point being made, but not in
any other way. And I for one would need to dig into the standard in
order to determine if such a class even satisfied the copyable etc.
requirements for an object to put into a vector (as std:auto_ptr, for
example, doesn't). And that's a pretty good warning (to me at least)
to "don't do that".

> Daniel Krügler mentions that changing the order would break most
> existing implementations. Unless someone can show a reason that
> implementations do need the freedom, I suspect that's the real reason:
> early vector implementations got it wrong, and now it's too late to
> change.

I think "got it wrong" is a definite mischaracterisation.

Seungbeom Kim

unread,
Jun 7, 2012, 12:36:29 AM6/7/12
to
On 2012-06-06 17:02, Christopher Dearlove wrote:
> On Jun 2, 1:53 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
>> It seems to me leaving destruction order implementation defined, is
>> giving the implementation a freedom that it doesn't need, while taking
>> away a guarantee that users sometimes do need.
>
> I don't see any sensible user needing that guarantee, even if it
> weren't for all the examples that show problems.

A user sensible enough could start something with an array, and then
later decide to switch to a vector. If a complex program crashes just
after switching from an array to a vector, the user will have to spend
a good amount of time debugging it in frustration.

(Indeed, lots of literature teach readers that they should avoid
raw arrays and substitute container classes wherever possible
because "arrays are evil", encouraging such switches.)

I agree that having containers remember the construction order is
asking too much, but I also agree that destruction in forward order
violates the principle of least surprise, though the degree of surprise
might be disagreed on.

> The original code was well-designed as a demonstration of the point
> being made, but not in any other way.

It's just how a problem buried in a complex real-world situation is
reduced to its essence and presented to others, as they'd better be.
Such a reduced form may of course seem unrealistic and artificial,
but it doesn't mean the problem is irrelevant.

> And I for one would need to dig into the standard in
> order to determine if such a class even satisfied the copyable etc.
> requirements for an object to put into a vector (as std:auto_ptr, for
> example, doesn't). And that's a pretty good warning (to me at least)
> to "don't do that".

The OP's example fails for a reason that has nothing to do with
the container requirements. Presumably, a container requirement
violation would be much easier to diagnose and debug.

--
Seungbeom Kim

Volker Lukas

unread,
Jun 7, 2012, 1:40:12 PM6/7/12
to
Daniel Krügler wrote:

> On 2012-05-31 06:20, PiotrN wrote:
>> I am curious is there any C++ standard rules about destruction of
>> std::vector elements.
>
> The standard does not specify the order of destruction of the
> elements. Neither does it do so for clear(), resize(), and other
> member functions that would destroy any element.
For vector resize it does specify "backwards" order, because erasing
must happen by calling pop_back as many times as necessary to shrink the
vector to its new size, if new size is lesser than old.

Nevin ":-]" Liber

unread,
Jun 7, 2012, 2:57:53 PM6/7/12
to
In article <jqp1tv$ebq$1...@usenet.stanford.edu>,
Seungbeom Kim <musi...@bawi.org> wrote:

> On 2012-06-06 17:02, Christopher Dearlove wrote:
> > On Jun 2, 1:53 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
> >> It seems to me leaving destruction order implementation defined, is
> >> giving the implementation a freedom that it doesn't need, while taking
> >> away a guarantee that users sometimes do need.
> >
> > I don't see any sensible user needing that guarantee, even if it
> > weren't for all the examples that show problems.
>
> A user sensible enough could start something with an array, and then
> later decide to switch to a vector. If a complex program crashes just
> after switching from an array to a vector, the user will have to spend
> a good amount of time debugging it in frustration.

Being dependent on order of destruction within a container is rare. And
once you learn you cannot rely on the containers doing it, you deal with
it. If you really need it, you can always make your own destructor
enforce it.

> (Indeed, lots of literature teach readers that they should avoid
> raw arrays and substitute container classes wherever possible
> because "arrays are evil", encouraging such switches.)

If we tighten the requirements on the destructor, what should the
following do:

v.clear()
v.erase(v.begin(), v.end())

Should other sequence containers also be changed? Arguably, people use
deques and lists for FIFOs, so they could use the guarantee too. (On
the other hand, you can still make a FIFO with push_front and pop_back.)

> It's just how a problem buried in a complex real-world situation is
> reduced to its essence and presented to others, as they'd better be.
> Such a reduced form may of course seem unrealistic and artificial,
> but it doesn't mean the problem is irrelevant.

My own feeling is that I wouldn't be opposed to this change, unless
library vendors have some compelling reason (such as efficiency) to keep
the status quo.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com>

Daniel Krügler

unread,
Jun 7, 2012, 3:01:31 PM6/7/12
to
Am 07.06.2012 19:40, schrieb Volker Lukas:
> Daniel Krügler wrote:
>
>> On 2012-05-31 06:20, PiotrN wrote:
>>> I am curious is there any C++ standard rules about destruction of
>>> std::vector elements.
>>
>> The standard does not specify the order of destruction of the
>> elements. Neither does it do so for clear(), resize(), and other
>> member functions that would destroy any element.
> For vector resize it does specify "backwards" order, because erasing
> must happen by calling pop_back as many times as necessary to shrink the
> vector to its new size, if new size is lesser than old.

This is an important observation, but I can ensure you, that this
wording change was *not* done to specify a specific order of destruction
for std::vector, but is was done to fix a problem with the previous
wording defined in terms of erase() as described in

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2033

bullet 4 of the issue description.

This looks like an unwanted side-effect of the issue and I think a new
issue is in order.

Greetings from Bremen,

Daniel Krügler


Seungbeom Kim

unread,
Jun 8, 2012, 12:24:43 AM6/8/12
to
On 2012-06-07 11:57, Nevin ":-]" Liber wrote:
> In article <jqp1tv$ebq$1...@usenet.stanford.edu>,
> Seungbeom Kim <musi...@bawi.org> wrote:
>>
>> A user sensible enough could start something with an array, and
>> then later decide to switch to a vector. If a complex program
>> crashes just after switching from an array to a vector, the user
>> will have to spend a good amount of time debugging it in
>> frustration.
>
> Being dependent on order of destruction within a container is rare.

That is probably so, though others may disagree.

Then, as I paid attention to what may happen when switching from
arrays to vectors, I wonder why arrays have a specified order of
destruction in the first place, and why even temporaries do.

On the other hand, I also wonder if implementations really need the
freedom of the destruction order.

> If you really need it, you can always make your own destructor
> enforce it.

You mean, by writing your own container class with the destructor
enforcing the destruction order of its elements? You certainly can,
but it's off the topic here.

> If we tighten the requirements on the destructor, what should the
> following do:
>
> v.clear()
> v.erase(v.begin(), v.end())
>
> Should other sequence containers also be changed? Arguably, people
> use deques and lists for FIFOs, so they could use the guarantee too.
> (On the other hand, you can still make a FIFO with push_front and
> pop_back.)

I think it would have been nice with a reverse order of destruction
specified for these as well, unless there had not been a reason
otherwise. It's natural and not less efficient than the forward
order; you feel much more comfortable popping from the back than from
the front, don't we? ;-)

The violation of the principle of least surprise is much less
significant here, though, because arrays don't have such member
functions.

--
Seungbeom Kim

Nevin :-] Liber

unread,
Jun 8, 2012, 2:53:32 AM6/8/12
to
In article <jqr8d9$o6e$1...@usenet.stanford.edu>,
Seungbeom Kim <musi...@bawi.org> wrote:

> On 2012-06-07 11:57, Nevin ":-]" Liber wrote:
> > In article <jqp1tv$ebq$1...@usenet.stanford.edu>,
> > Seungbeom Kim <musi...@bawi.org> wrote:
> >>
> >> A user sensible enough could start something with an array, and
> >> then later decide to switch to a vector. If a complex program
> >> crashes just after switching from an array to a vector, the user
> >> will have to spend a good amount of time debugging it in
> >> frustration.
> >
> > Being dependent on order of destruction within a container is rare.
>
> That is probably so, though others may disagree.
>
> Then, as I paid attention to what may happen when switching from
> arrays to vectors, I wonder why arrays have a specified order of
> destruction in the first place, and why even temporaries do.
>
> On the other hand, I also wonder if implementations really need the
> freedom of the destruction order.
>
> > If you really need it, you can always make your own destructor
> > enforce it.
>
> You mean, by writing your own container class with the destructor
> enforcing the destruction order of its elements?

Nothing so drastic. For instance, you can have a wrapper that forces
the behavior, as in:

template<typename C>
struct ForceDestructionOrder
{
explicit ForceDestructionOrder(C& c) : _c(c) {}

~ForceDestructionOrder()
{ while (!_c.empty() { erase(--_c.end()); } }
private:
C& _c;
};

And usage:

class Foo
{
// ...
std::vector<Bar> _vb;
ForceDestructionOrder<decltype(_vb)> _d;
// ...
};

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

Dave Harris

unread,
Jun 9, 2012, 2:37:33 PM6/9/12
to
christophe...@googlemail.com (Christopher Dearlove) wrote (abridged):
> On Jun 2, 1:53 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
> > It seems to me leaving destruction order implementation defined,
> > is giving the implementation a freedom that it doesn't need, while
> > taking away a guarantee that users sometimes do need.
>
> I don't see any sensible user needing that guarantee,

Why was my example not sensible? In this case it's not so much
"needing", as being least surprising and most efficient. Destruction
in reverse order is O(N), destruction in forward order still works
but is O(N*N) because of extra list traversal.

Francis Glassborow seemed to imply that destruction order was
important only when the elements reference each other. My example
was of a case where they don't. Another example would be if the
elements held locks, and unlocking them in the wrong order could
lead to deadlocks. In any case where the destructors have visible
side-effects, destruction order could matter.


> even if it weren't for all the examples that show problems.

The only problems concerned the difficulty of tracking construction
order in the face of swaps and insertions. I don't think anyone
actually advocated that: it's a straw doll. The suggestion is
simply destruction in reverse index order. No-one has posted an
example showing problems with that.


> The original code was well-designed as a demonstration of the
> point being made, but not in any other way.

What was ill-designed about my code?


> And I for one would need to dig into the standard in order
> to determine if such a class even satisfied the copyable etc.
> requirements for an object to put into a vector (as std:auto_ptr,
> for example, doesn't). And that's a pretty good warning (to me
> at least) to "don't do that".

My class would be copyable and movable. Why wouldn't it be? You seem
to be inventing faults which aren't there.

-- Dave Harris, Nottingham, UK.


Dave Harris

unread,
Jun 9, 2012, 2:38:05 PM6/9/12
to
ne...@eviloverlord.com ( Liber) wrote (abridged):
> Being dependent on order of destruction within a container is rare.

Agreed. However, the point remains. Why take away a guarantee from
users, albeit one that is needed rarely, if the corresponding freedom
isn't needed at all by implementors?


> And once you learn you cannot rely on the containers doing it,
> you deal with it. If you really need it, you can always make
> your own destructor enforce it.

Agreed. We can work around design flaws in the library. Again, why
should we need to? No-one has yet produced a convincing argument for
it not being a design flaw.


> If we tighten the requirements on the destructor, what should the
> following do:
>
> v.clear()
> v.erase(v.begin(), v.end())

Destroy in reverse index order. Why not?


> Should other sequence containers also be changed?

Unless there's a good reason not to. For singly-linked lists, for
example, it would be impractical. For unordered_map, there is a clue
in the name (ie it makes sense not to define the order). For a normal
map, which has a well-defined order and may be used as an over-blown
vector, then a defined destruction order could be useful.

-- Dave Harris, Nottingham, UK.


--

Christopher Dearlove

unread,
Jun 11, 2012, 9:40:09 AM6/11/12
to
On Jun 9, 7:38 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
> Destroy in reverse index order. Why not?

Because it's a false sense of security. It only works if you use the
vector in a specific way. It doesn't work with general use of a
vector.

Christopher Dearlove

unread,
Jun 11, 2012, 9:41:38 AM6/11/12
to
On Jun 9, 7:37 pm, brang...@cix.compulink.co.uk (Dave Harris) wrote:
> What was ill-designed about my code?

Obviously that it depended on destruction order of a vector.

But that's a symptom of the fact that it's fragile, containing non-
owning pointers that have the potential to bite you hard if not
carefully managed. And putting them in a vector turns out not to be
that. Of course sometimes there are reasons for that. But mostly it's
something to avoid.

Dave Harris

unread,
Jun 13, 2012, 12:20:43 AM6/13/12
to
christophe...@googlemail.com (Christopher Dearlove) wrote (abridged):
> > What was ill-designed about my code?
>
> Obviously that it depended on destruction order of a vector.

So vector doesn't support it because it's bad, and it's bad because
vector doesn't support it. I see.


> But that's a symptom of the fact that it's fragile, containing non-
> owning pointers that have the potential to bite you hard if not
> carefully managed. And putting them in a vector turns out not to
> be that.

The items in the vector don't contain any pointers. Even if they did,
non-owning pointers are not intrinsically bad. In this case they are
easy to manage, because the item constructor and destructor do all
that is required in a well-defined way. The only issues are caused
by vector, and would not be issues with a plain C array, or if vector
was more consistent with plain C arrays.

-- Dave Harris, Nottingham, UK.


christophe...@googlemail.com

unread,
Jun 13, 2012, 11:26:26 AM6/13/12
to
On Wednesday, June 13, 2012 5:20:43 AM UTC+1, Dave Harris wrote:
> In this case they are
> easy to manage, because the item constructor and destructor do all
> that is required in a well-defined way.

A way that imposes rules on the user as to what he may or may not do, rather
than the software enforcing it. There needs to be a good reason to do that.
Sometimes there is, but none has been suggested here.

> The only issues are caused
> by vector, and would not be issues with a plain C array, or if vector
> was more consistent with plain C arrays.

No, you'd still be stuck with having to obey rules like "when putting this
into a vector, you may not use the following vector functions: push_front,
..." with no compiler/language support to prevent you getting it wrong.

Of course you may say, there's no compiler support to stop you putting these
things in a vector as things are. That's true. But I think (trying to put
opinion on one side) the choices are:

- Write the class so it doesn't have restrictions (of this type).
- Write the class as in the example with rules given to the user that
include "don't use vector".
- Change vector as you want, write the class as in the example with rules
given that include "don't use the following vector functions: ...".

I'm hoping we can agree to disagree on the best ordering of those choices.
Though it does depend on the ease/cost of doing the first in the real case.
(I'm ignoring the practicality issue of changing vector, though of course
that's actually the hardest thing of all.)

PiotrN

unread,
Jun 14, 2012, 12:58:11 PM6/14/12
to
On 11 Cze, 15:41, Christopher Dearlove
<christopher.dearl...@googlemail.com> wrote:
>
> But that's a symptom of the fact that it's fragile, containing non-
> owning pointers that have the potential to bite you hard if not
> carefully managed. And putting them in a vector turns out not to be
> that. Of course sometimes there are reasons for that. But mostly it's
> something to avoid.
>

The example code from which I started this discussion is just an
example - nothing more.
It is not from real world project.
I was really surprised that destruction order in std::vector differs
from that in arrays and it breaks the "reverse order of destruction"
rule which is so common in C++.
I know that my example is not safe and not very wise - but it never
pretend to be safe and smart.

I would rather know your opinion about the case - wouldn't be better
to change this order in ~std::vector() destructor?

Let's look at std::vector (from Gnu GCC) implementation. It wouldn't
be a big effort to change the order:

~vector() { std::_Destroy(this->_M_impl._M_start, this-
>_M_impl._M_finish); }
// ommiting some indirect steps (__false_type here means non trivial
destructor)
template<typename _ForwardIterator>
inline void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last,
__false_type)
{ for ( ; __first != __last; ++__first)
std::_Destroy(&*__first); } // std::_Destroy(&*__first) means calling
destructor: p->~T()


Define something named __destroy_reverse_aux for
bidirectional_iterator_tag iterators and use it for
std::vector<>::~vector() does not seem to be a big effort for compiler
vendors ;)

Thanks,
Piotr Nycz

Christopher Dearlove

unread,
Jun 15, 2012, 2:26:33 PM6/15/12
to
{ Reformatted; please limit your lines to 70 chars -mod/we }

On Thursday, June 14, 2012 5:58:11 PM UTC+1, PiotrN wrote:
> The example code from which I started this discussion is just an
> example - nothing more.

OK, a confusion here. My original comment was that the code was
ill-designed, except as an illustration of the problem. As you say,
that's what it was designed for.

But then Dave Harris asked what was ill-designed about "my
code". Without checking I assumed that since the only code I'd
commented on was the original code, that he was the OP (rather than
you) and made additional comments. If he's not the OP, I have no
comments on any code of his, I don't know what code he's referring to.

Just to add to the confusion, the post from an unnamed user is me, due
to a change in new Google Groups (unfortunately no longer get a proper
Usenet feed). Commenting unfavourably on that would be off-topic, so I
won't.

So I have some C++ content:
- The original code just demonstrated a point, it does that, thanks.
- With vector unspecified you can write simple rules like "don't use
vector if order of destruction matters".
- If vector were changed to be reverse order destruction, that rule
would have to become "don't use the following vector functions
... if order of destruction matters".
- Some might view the possibility of some use of vector that way a
gain, others (including me) would think that it just creates a more
complicated situation.
- The most obvious questions in a design is "Why does the order of
destruction matter? What's the gain? Is it big enough to prefer this
fragile design to one where it doesn't matter?". The answer to the
last question could be yes, but would need to have at least have a
plausible argument (or possibly a reverse challenge, "Show me a
better way!").

PiotrN

unread,
Jun 16, 2012, 2:20:27 AM6/16/12
to
On 15 Cze, 20:26, Christopher Dearlove
<christopher.dearl...@googlemail.com> wrote:
> - The most obvious questions in a design is "Why does the order of
> destruction matter? What's the gain? Is it big enough to prefer this
> fragile design to one where it doesn't matter?". The answer to the
> last question could be yes, but would need to have at least have a
> plausible argument (or possibly a reverse challenge, "Show me a
> better way!").
>

Let's look at this very simple example:
int main() {
string a;
string b;
}
We all know that a is constructed before b, and, b is destructed
before a. This is the language rule. It is not a must to use it.
Everyone is free to use it - or just ignore, as in the case that the
order of destruction would be not defined by C++ standard.
At the top of this discussion, I pointed that order of destruction is
defined for static and dynamic arrays - but it is not defined for
std::vector (actually Daniel Krügler confirmed this missing rule in
standard).
If such rule for std::vector was added - then it should not break any
existing code - as there is not any rule for std::vector now. Of
course, no one would be enforced to use it in their code.

And there is one obvious advantage - in arrays - reverse order rule is
a fact. If someone uses this rule in their code - then replacing
arrays with std::vector would be safer than it is now.

I showed in my last entry to this thread that implementing this rule
in GNU GCC shouldn't be a big issue.

A possible real life example for this? Let's imagine a critical
section you want to lock many mutexes. Then, probably, the best would
be to unlock them in reverse order. The best way is to implement
scopeGuards for lock on a mutex (ScopeGuard ctor locks mutex, dtor
unlocks it). So - a local array of ScopeGuards does what them wanted.
Let's imagine in some refactoring of this design someone wants to be
very smart - and they replace arrays with vectors. And what? The
system changes its behavior. No one knows why... Who could ever
imagine that destruction order in arrays differs from this in
vectors...

Thanks,
Piotr Nycz

Christopher Dearlove

unread,
Jun 18, 2012, 12:57:39 PM6/18/12
to
On Saturday, June 16, 2012 7:20:27 AM UTC+1, PiotrN wrote:
> I pointed that order of destruction is
> defined for static and dynamic arrays - but it is not defined for
> std::vector (actually Daniel Krügler confirmed this missing rule in
> standard).

Missing suggests that it should have been there but was omitted. But
the point you still haven't addressed is that it's impossible to
define a safe destruction order for vector. It's only possible to
define a safe destruction order for some uses of vector.

> And there is one obvious advantage - in arrays - reverse order rule is
> a fact. If someone uses this rule in their code - then replacing
> arrays with std::vector would be safer than it is now.

But then when someone decided to change how they used that vector it
would be unsafe again. That makes the "help the people who don't know
what they are doing" argument rather weak. At some point they'll get
bitten.

PiotrN

unread,
Jun 18, 2012, 4:50:18 PM6/18/12
to
On 18 Cze, 18:57, Christopher Dearlove
<christopher.dearl...@googlemail.com> wrote:
>
> But then when someone decided to change how they used that vector it
> would be unsafe again. That makes the "help the people who don't know
> what they are doing" argument rather weak. At some point they'll get
> bitten.
>

You are missing one point which I mentioned already several timer.
Order of std::vector destruction is undefined now. So, nobody shall
use this not defined order in their code/design. Thus defining this
order in any way (let's say in this order: 0,7,5,1,4, etc...) shall
not cause for anybody to get bitten.

But I asked this question to stackoverflow and there I found
reasonable answer why not define this order and let implementation be
free in this subject. OF course - performance reason.

see
http://stackoverflow.com/questions/11085187/would-it-be-reasonable-to-define-destruction-order-of-vector-elements


Thanks,
Piotr Nycz

Dave Harris

unread,
Jun 18, 2012, 4:51:40 PM6/18/12
to
christophe...@googlemail.com () wrote (abridged):
> > In this case they are easy to manage, because the item
> > constructor and destructor do all that is required in a
> > well-defined way.
>
> A way that imposes rules on the user as to what he may or may not
> do, rather than the software enforcing it.

In my example, there are no restrictions. Some usage patterns
are more efficient than others. Some are simply more expected.

Even if there were restrictions that affect correctness, that's
not a problem. Typically, either the usage is local, so there is
no other "user" who needs rules imposed on them, or else the vector
is encapsulated by a class that enforces the rules.

It would be possible to have bugs, of course. Few are the classes that
cannot be misused. The compiler doesn't prevent us doing more pushes
than pops on a stack, for example. That a feature can be misused by
poor programmers not a sufficient reason to deny it to good ones.


> No, you'd still be stuck with having to obey rules like "when
> putting this into a vector, you may not use the following
> vector functions:
> push_front,
> ..." with no compiler/language support to prevent you getting it
> wrong.

The suggestion is that vector destroy its elements in reverse
index order. There are no special cases or caveats, no restrictions
on what vector functions can be called.

-- Dave Harris, Nottingham, UK.


Christopher Dearlove

unread,
Jun 19, 2012, 1:19:44 PM6/19/12
to
On Monday, June 18, 2012 9:51:40 PM UTC+1, Dave Harris wrote:
> The suggestion is that vector destroy its elements in reverse
> index order. There are no special cases or caveats, no restrictions
> on what vector functions can be called.

But there are (or would be) restrictions on which vector functions
could be called in order that this corresponded to the order of
construction, reversing that being the reason for it. So in practice
there are restrictions on what vector functions can be called in order
that your proposal has any use. Thus in reality there would be special
cases. (In other words, no restriction on what can be called. Just
restrictions on what can be called and works.)

PiotrN

unread,
Jun 19, 2012, 6:30:05 PM6/19/12
to
On 19 Cze, 19:19, Christopher Dearlove
<christopher.dearl...@googlemail.com> wrote:
>
> But there are (or would be) restrictions on which vector functions
> could be called in order that this corresponded to the order of
> construction, reversing that being the reason for it. So in practice
> there are restrictions on what vector functions can be called in order
> that your proposal has any use. Thus in reality there would be special
> cases. (In other words, no restriction on what can be called. Just
> restrictions on what can be called and works.)
>

I am really trying, but I do not understand your point. Could you
give us <10 lines example explaining your objections?

BTW, I recently received the information from Howard Hinnant on SO
that libc++ http://libcxx.llvm.org/ does the vector elements
destruction in backward order. What do you think? Do they have
"restrictions on what can be called and works"?

HTH,
Piotr Nycz

Dave Harris

unread,
Jun 24, 2012, 8:29:52 AM6/24/12
to
christophe...@googlemail.com (Christopher Dearlove) wrote
(abridged):
> On Monday, June 18, 2012 9:51:40 PM UTC+1, Dave Harris wrote:
> > The suggestion is that vector destroy its elements in reverse
> > index order. There are no special cases or caveats, no
> > restrictions on what vector functions can be called.
>
> But there are (or would be) restrictions on which vector functions
> could be called in order that this corresponded to the order of
> construction, reversing that being the reason for it. So in practice
> there are restrictions on what vector functions can be called in
> order that your proposal has any use. Thus in reality there would be
> special cases. (In other words, no restriction on what can be
> called. Just restrictions on what can be called and works.)

If the sequence order is important for correctness, then the
programmer would need to keep the order correct. I don't see any
special difficulty here. For comparison, if I am using a binary
search, and I need to keep the vector sorted, then push_back() is
unlikely to do the right thing. Vector provides tools to be used; it
is up to the programmer to use them correctly.

-- Dave Harris, Nottingham, UK.


0 new messages