Re: setter for deleter in boost::shared_ptr (and alike)
Alf P. Steinbach wrote:
* James Dennett:
Alf P. Steinbach wrote:
* James Dennett:
Alf P. Steinbach wrote:
* Alberto Ganesh Barbati:
Alf P. Steinbach ha scritto:
* Alberto Ganesh Barbati:
Alf P. Steinbach ha scritto:
* Abhishek Padmanabh:
Why doesn't boost::shared_ptr<> provide a setter for the deleter
when
it provides a getter?
What's provided is a pointer to the deleter function pointer or
functor
object,
template<class D, class T>
D * get_deleter(shared_ptr<T> const & p);
Since there's no 'const' that pointer can used to change the
deleter function.
It's true that with the pointer returned by get_deleter() you can
call
non-const functions on the deleter, however you still can't
replace it
with another (possibly unrelated) deleter
I see no wording to that effect, neither in TR1 nor the draft
standard.
If you would care to cite chapter & verse, please?
The onus of the prove is on you.
You have maintained that given a pointer of type
D* p;
one "can't replace [the referent]", i.e. you say that one can't do
*p = aDValue;
Well that's utter nonsense.
No, it's not. You can do that only if you know the type of
the deleter and the deleter chooses to allow assignment,
Yes. In other words, it's false, incorrect and nonsense that you can't
do it.
No, that's misleading.
What's misleading and who's misleading?
You can assign.
First response to Alberto I provided a concrete, complete example program.
The effect of which was also included, effect being to change the delete
action (what actually /happens/ when a shared_ptr invokes the deleter).
Saying otherwise is misleading and utter nonsense.
You can sometimes change its state,
but you cannot change its identity or type.
Again, that's too subtle for me, sorry.
If Alberto's statement "you can't" was that you can't change the static
type of *p, well, that's true in the same way you can't change the type
of
int x;
but that's irrelevant to anything, utter nonsense.
If the statement "you can't" was that you can't change the effect of the
shared_ptr's delete action, well, that was demonstrated as false by
trivial actual code and output -- it's just nonsense.
You *may* be able to assign to it,
There is no "may" about it.
Unless you're talking again about an inaccessible assignment operator,
which has nothing to do with what shared_ptr enforces or not.
Of course it has to do with that. The design of shared_ptr<> opting for
get_deleter and leaving out
template < typename D >
set_deleter( D d )
is enforcing that the type of the deleter cannot be changed. That client
code _can_ disable assignment is a direct consequence of the guarantees
made by shared_ptr.
We should not loose sight of the main contention that the return type of
get_deleter() being non-const is a design flaw. That has been claimed by
you (but not demonstrated). Others have issues with that. The discussion of
whether "replace" means change value or means change object identity is an
irrelevant side issue (on which you happen to mistaken, too).
I guess I could allow the theoretical possibility that shared_ptr keeps
a redundant copy of the deleter for the one and only purpose of foiling
assignment attempts via get_deleter's result, where the only purpose of
the non-const-ness of get_deleter is to allow assignments to the hidden
copy. Sort of to trick programmers. But hey, that's, well, nonsense.
but that's not as interesting to me
as it seems to be to you -- definitely something of a side
issue.
I'm sorry, but that's not correct. I'm just responding to claims that
the you can't do something that any novice can see you can, and that's
been demonstrated by an actual program. The interest is not mine,
except that there's a const correctness that needs to be addressed.
Right. This should be about const-correctness. It has been demonstrated in
code that the non-const return type does not prevent (or make difficult)
safe usage of shared_ptr, i.e., at the point where you say
shared_ptr ptr ( new X ... , my_deleter );
the type of my_deleter is _your_ choice. If it is class type. you _know_
which operator() will be executed upon deletion. No subsequent assignmen
can void the guarantess you put into this line.
So what exactly is the flaw?
and
even then you've not replaced the deleter, you've simply
changed its value.
Again, that's too subtle for me, I'm afraid. I don't know /what/
Alberto meant by "replace", used in the context of assignment. But if
it was something that is irrelevant, then it's, well, irrelevant... :-)
It's very relevant. The deleter can be changed when the
owned object is changed -- and that means we can change
everything about it, including its type (and hence its
identity). No such change is possible without changing
the owned object, and to ignore that fact is to miss the
meat of the argument.
Again, that's too subtle for me.
I've demonstrated by actual code that you can change the delete action,
what actually /happens/ when a shared_ptr invokes its deleter, at will
(if there is an accessible operator of course).
That is possible if the type of the deleter is a function pointer. For class
types, the code of operator()(T*) will be executed no matter what you try.
I agree that the ideal would be that you couldn't.
I disagree that this would be idea. Somehow, my previous post did not get
through, so I reproduce the use case here:
template < typename T >
class MyDeleter {
typedef std::tr1::function< void(T*) > command;
std::list< command > bye_bye;
public:
template < typename Command >
void push_command ( Command c ) {
bye_bye.push_back( c );
}
void operator() ( T * t_ptr ) const {
for ( std::list< command >::const_iterator iter = bye_bye.begin();
iter != bye_bye.end(); ++ iter ) {
(*iter)(t_ptr);
}
free (t_ptr);
}
};
Note that this deleter has an accessible assignment operator. Indeed, you
can use that to ditch all registered actions, but you cannot use it to
change the deletion from free() to, says, delete[].
Now, that is clearly a use case. It far outweighs, in my opinion, the
possible dangers of using shared_ptr<> with a stupid deleter.
So there's really nothing further to discuss until someone steps forward
and /defines/ what is meant by the so far metaphysical "replace" that
isn't "change" -- I've asked many times, but no definition so far.
Recall the definition of "object": it is a region in memory. What is stored
there is the value of the object. The same object can have different values
and calls to non-const member functions or calls to the assignment operator
do change the value of the underlying object, which however, remains the
same region of memory. Just taken literally, assignment does not replace
the object by a different object. This is why assignment does not
invalidate references.
Now for the deleter in shared_ptr. A hypothetical setter function like
template < typename D >
set_deleter( D d );
would replace the current deleter object by a different object (in the
process, the old deleter object is destroyed, the deleter type may change
and so may the region of memory). The assignment of your example code does
not do that. The assignment simply changes the value.
There is nothing subtle about that. It's just a simple consequence of the
definition of "object". That definition gives a criterion of sameness and
therefore allows to deduce the meaning of "replace" (which is supposed to
affect the sameness).
Best
Kai-Uwe Bux
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]