Re: [boost] Is there any interest in a library that provides cont ainers with virtual destructors?

----Original Message---- From: Victor A. Wagner Jr. [mailto:vawjr@rudbek.com] Sent: 26 October 2005 15:16 To: boost@lists.boost.org; 'boost@lists.boost.org' Subject: Re: [boost] Is there any interest in a library that provides cont ainers with virtual destructors?
At 02:51 2005-10-26, Martin Bonner wrote:
----Original Message---- From: Victor A. Wagner Jr. [mailto:vawjr@rudbek.com] Sent: 26 October 2005 05:36 To: boost@lists.boost.org; boost@lists.boost.org Subject: Re: [boost] Is there any interest in a library that provides containers with virtual destructors?
At 10:04 2005-10-25, Andy Tompkins wrote:
I have read a few times that people sometimes wish that std::vector (or other containers) had a virtual destructor. [snip] This allows one to write something like:
struct person { string first_name; string last_name; }; class people : public virtual_vector<person> { public: //extra methods };
Is this useful?
unless I mis-read (or mis-understood...far more likely) a lot of books on how C++ works, I don't believe there is any reason for what _you've_ shown to need a virtual destructor.
You have mis-read or mis-understood (or you need better books). Consider: virtual_vector<person>* p = new people;
I guees I wasn't clear.. I was suggesting that virtual_vector has no need for existence.
delete p; That invokes undefined behaviour unless virtual_vector<person> has a virtual destructor.
are you suggesting that if it were class people: public std::vector<person> {.....}; as above the same would be true? not "in practice", "in theory".
Absolutely. See 5.3.5/1 of the standard where this is explicitly called out as undefined behaviour. -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434

I have read a few times that people sometimes wish that std::vector (or other containers) had a virtual destructor. [snip] This allows one to write something like:
struct person { string first_name; string last_name; }; class people : public virtual_vector<person> { public: //extra methods };
Is this useful?
unless I mis-read (or mis-understood...far more likely) a lot of books on how C++ works, I don't believe there is any reason for what _you've_ shown to need a virtual destructor.
You have mis-read or mis-understood (or you need better books). Consider: virtual_vector<person>* p = new people;
I guees I wasn't clear.. I was suggesting that virtual_vector has no need for existence.
delete p; That invokes undefined behaviour unless virtual_vector<person> has a virtual destructor.
are you suggesting that if it were class people: public std::vector<person> {.....}; as above the same would be true? not "in practice", "in theory".
Absolutely. See 5.3.5/1 of the standard where this is explicitly called out as undefined behaviour.
Yes, it you are trying to delete pointers to 'people' through base class you do need virtual destructor. But: 1. In general in bad idea to inherit from STL container. Most probably you need a different relatationship (hint: containment) 2. If you insist on inheritance you still in most cases wouldn't need virtual destructor: don't delete through pointers on vector. To reinforce this you could employ either private inheritance or protected destructor in wrapper around vector. In any case this is not a type of idiom anyone need to promote. Gennadiy

[deleted]
are you suggesting that if it were class people: public std::vector<person> {.....}; as above the same would be true? not "in practice", "in theory".
Absolutely. See 5.3.5/1 of the standard where this is explicitly called out as undefined behaviour.
5.3.5/1 looks like this in my copy of the standard ISO/IEC 14882 Second edition 2003-10-15 5.3.5 Delete [expr.delete] 1 The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression. delete-expression: ::opt delete cast-expression ::opt delete [ ] cast-expression The first alternative is for non-array objects, and the second is for arrays. The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. The result has type void. perhaps some other paragraph? this doesn't address anything about derived objects.
Yes, it you are trying to delete pointers to 'people' through base class you do need virtual destructor. But:
1. In general in bad idea to inherit from STL container.
yet to be demonstrated, though asserted often
Most probably you need a different relatationship (hint: containment) 2. If you insist on inheritance you still in most cases wouldn't need virtual destructor: don't delete through pointers on vector. To reinforce this you could employ either private inheritance or protected destructor in wrapper around vector.
In any case this is not a type of idiom anyone need to promote.
I disagree and will recapitulate the conversation thread with all "changes" included so as to avoid confusion. struct person { string first_name; string last_name; }; person is a type and represents a concrete type. These can be new'd and delete'd at whim, put in STL containers, whatever. Just your almost ordinary C++ struct (not POD because of the non-trivial destructor needed for the strings). typedef std::vector<person> vecperson; Another concrete type, newable. deleteable, and containable with no special considerations. struct choir { vecperson SATB; ///some methods that play with SATB, NO additional data ///the only reason the destructor for THIS class is special is because of the need to destruct SATB /// sizeof(vecperson) == sizeof(choir) }; yet another concrete class, still nothing special, newable, deletable, containable. now for the final step; struct people: vecperson { ///some methods only, no data ///nontrivial constructor as choir, but we still have /// sizeof(vecperson) == sizeof(people) }; I submit that people is a concrete type, with no restrictions on newing deleting, or containing. which means that people* p = new people; delete p; is legal, well formed, and the behavior is defined. NOW if the question everyone else answered is can you do this? vecperson* pv = new people; delete pv; I _suspect_ that it will work just fine, but I'm not interested in that problem, nor was there any indication in the OP that it was a requirement. Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On 10/26/05, Victor A. Wagner Jr. <vawjr@rudbek.com> wrote:
perhaps some other paragraph? this doesn't address anything about derived objects.
Just look 2 paragraphs further: 5.3.5 paragraph 3 "In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor or the behavior is undefined." ... The paragraph then goes further to talk about arrays. As for interest in the STL containers with virtual destructors, I'd personally say no. I've never encountered a situation where it would be useful or at least useful and better than other alternatives. Anyway, the desire for a virtual destructor could exist with any type. If someone wants virtual destructors for STL containers, then what next? multi_array with virtual destructors? graphs? Forgive me if that sounds like a slippery slope argument, but really I see no logic as to why one would want virtual destructors for STL containers yet not any other types. You can use the same type of argument for any type you can think of -- "I want to derive from the type and then add functionality, but want to delete it via a pointer to the base class". Does this mean that all types should have one version with virtual destructors, and one without? Definately not. I just don't see why someone would want to make the exception for STL containers. -- -Matt Calabrese

struct people: vecperson { ///some methods only, no data ///nontrivial constructor as choir, but we still have /// sizeof(vecperson) == sizeof(people) };
I submit that people is a concrete type, with no restrictions on newing deleting, or containing.
I do not question it is valid C++. It is also an example of bad practice. people is not just a vector of person - I dare to submit they are much more. Yet we could implement model of people using some collection of persons (amoung other things). What I am trying to say is that here is a clear example of confusion of "IMPLEMENTED WITH" relationthip with "IS A". And in most cases when someine trying to inherit from collection this is the case.
NOW if the question everyone else answered is can you do this?
vecperson* pv = new people; delete pv;
I _suspect_ that it will work just fine,
It will, but only for the definition above. As soon as you got nontrivial destructor in people I _am sure_ it won't anymore
but I'm not interested in that problem, nor was there any indication in the OP that it was a requirement.
My understanding is that making it work always was a primary goal of OP.

At 23:28 2005-10-26, Gennadiy Rozental wrote:
struct people: vecperson { ///some methods only, no data ///nontrivial constructor as choir, but we still have /// sizeof(vecperson) == sizeof(people) };
I submit that people is a concrete type, with no restrictions on newing deleting, or containing.
I do not question it is valid C++. It is also an example of bad practice. people is not just a vector of person - I dare to submit they are much more. Yet we could implement model of people using some collection of persons (amoung other things). What I am trying to say is that here is a clear example of confusion of "IMPLEMENTED WITH" relationthip with "IS A". And in most cases when someine trying to inherit from collection this is the case.
OK, fix the core language so that I don't have to write the whole batch of forwarding functions, AND I get the new ones automatically when std::vector gets updated!! No??? don't wanna do that? then it ISA std::vector<> (or whatever STL collection I choose)!!
NOW if the question everyone else answered is can you do this?
vecperson* pv = new people; delete pv;
I _suspect_ that it will work just fine,
It will, but only for the definition above. As soon as you got nontrivial destructor in people I _am sure_ it won't anymore
but I'm not interested in that problem, nor was there any indication in the OP that it was a requirement.
My understanding is that making it work always was a primary goal of OP.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

OK, fix the core language so that I don't have to write the whole batch of forwarding functions, AND I get the new ones automatically when std::vector gets updated!! No??? don't wanna do that? then it ISA std::vector<> (or whatever STL collection I choose)!!
Actually you don't necessarily need to write forwarding functions you could use private inheritance and employ using. I brings it's own limitations though. Gennadiy

At 10:03 2005-10-27, you wrote:
OK, fix the core language so that I don't have to write the whole batch of forwarding functions, AND I get the new ones automatically when std::vector gets updated!! No??? don't wanna do that? then it ISA std::vector<> (or whatever STL collection I choose)!!
Actually you don't necessarily need to write forwarding functions you could use private inheritance and employ using. I brings it's own limitations though.
don't I still have to do a using for each method? that means I do NOT get all the nifty new methods for my class when TR9 is released. Ah well, I'll be over 100years old by then, I'll let the young whippersnappers take care of updating the code.
Gennadiy
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On 10/27/05, Victor A. Wagner Jr. <vawjr@rudbek.com> wrote:
OK, fix the core language so that I don't have to write the whole batch of forwarding functions, AND I get the new ones automatically when std::vector gets updated!! No??? don't wanna do that? then it ISA std::vector<> (or whatever STL collection I choose)!!
Don't use an IS-A relationship just because you want to save time typing. Use an IS-A relationship if IS-A makes sense. If you really always want all of vector's operations exposed without additional typing, then just encapsulate it and make it public. If you want the member functions to be a direct part of the encapsulating class, then use private inheritance and promote the member functions and types from the vector base class to your type's public interface with using-delcarations. -- -Matt Calabrese
participants (4)
-
Gennadiy Rozental
-
Martin Bonner
-
Matt Calabrese
-
Victor A. Wagner Jr.