[Insight-users] itk::SmartPointer - problem making code const-correct
Luis Ibanez
luis.ibanez at kitware.com
Sat May 29 10:58:51 EDT 2010
Hi Stuart,
--------------------------------------------------------------
On Fri, May 28, 2010 at 1:24 PM, Stuart Golodetz <itk at gxstudios.net> wrote:
> Hi Luis,
>
> Thanks for the helpful response.
> 1) When writing functions that take an image as an argument,
>
> we usually use a Raw pointer instead of a Smart Pointer.
>
> The reason is that SmartPointers will not do polymorphism.
>
> That is, if you use smart pointers, you can call that function
> later with an argument that is a derived class of that image
> type.
>
> Not sure I follow what you mean here - if SmartPointers don't support
> polymorphism, then doesn't that mean that this sort of thing won't work?
>
> struct B { virtual ~B() {} };
> struct D : B {};
> void f(itk::SmartPointer<B> b) {}
> ...
> itk::SmartPointer<D> d;
> f(d);
>
>
Exactly.
This code above doesn't work.
Here is a full example that illustrates the case:
----------------------------------------------------
#include "itkImage.h"
#include "itkObject.h"
class B : public ::itk::Object
{
virtual ~B() {}
};
class D : public B {};
void f(itk::SmartPointer<B> b) {}
void g( B * b) {}
int main()
{
itk::SmartPointer<D> d;
g(d); // This works
f(d); // This doesn't
return 0;
}
---------------------------------------------------
> Whereas this always works by the rules of the language:
>
> void f(B *b) {}
> D *d;
> f(d);
>
> -------------------------
Yes,
This is the case that support polymorphism.
-------------------------
> I think I would understand what you mean if your last paragraph said "That
> is, if you use *raw* pointers..." [emphasis mine]. Or am I getting the wrong
> end of the stick? :)
>
> ------------------------
My mistake.
Thanks for pointing this out.
When I wrote
> That is, if you use smart pointers, you can call that function
> later with an argument that is a derived class of that image
> type.
I actually meant to write
> That is, if you use *raw* pointers, you can call that function
> later with an argument that is a derived class of that image
> type.
Sorry about the mishap.
----------------------------------------------------------------------------
> If you look at most ITK filters, you will find that raw pointers
> are used in the API, for passing and receiving images.
>
> However, when we call those functions we pass a SmartPointer
> to them (since SmartPointers know how to cast themselves as
> raw pointers).
>
>
> 2) The only case in which you may want to pass an image
> SmartPointer as argument to a function is when you are
> creating that image inside the function.
>
> In that case, passing the SmartPointer by reference is
> a reasonable choice.
>
> I think I've been trying to use itk::SmartPointer as a boost::shared_ptr,
> which may not be the best plan :) The idea being that the pointed-to image
> or whatever won't get destroyed as long as I'm holding an itk::SmartPointer
> to it, so I can construct it somewhere, pass the itk::SmartPointer into a
> function, store a copy of the itk::SmartPointer somewhere else and not worry
> if the original itk::SmartPointer to the image no longer exists.
>
> What I've been missing is that itk::SmartPointer appears to use *intrusive*
> reference-counting (i.e. the reference count is stored in the image itself),
> so that if I pass in a raw image pointer to a function I can then construct
> a separate itk::SmartPointer the other end from it that will share the
> reference count with the original itk::SmartPointer. Is that right?
>
That's exactly right.
The actual "reference count" is stored in the image.
More specifically in the member variable:
m_ReferenceCount
which is defined in itkLightObject.h : line 141.
and the image inherits it through the chain:
itk::LightObject
itk::Object
itk::DataObject
itk::ImageBase
itk::Image
> 3) Please note that the construction
>
> const Image::ConstPointer & ptr ....;
>
> prevents the internal mechanisms of the SmartPointer
> from working, since the "const" keyword prevents the "ptr"
> variable from changing. (strictly speaking it prevents the
> smart pointer from calling the non-const method Register()
> on the object that it points to).
>
> Offhand, I think that could be easily changed by making Register() and
> UnRegister() const methods, since that would only have the effect of making
> m_Pointer itself const, not the ObjectType it points to:
>
> /** The pointer to the object referrred to by this smart pointer. */
> ObjectType* m_Pointer;
>
> void Register() --> const <--
> {
> if(m_Pointer) { m_Pointer->Register(); }
> }
>
> void UnRegister() --> const <--
> {
> if(m_Pointer) { m_Pointer->UnRegister(); }
> }
>
>
Yes,
Ideally these methods should have been "const".
Since the reference count of the object doesn't
really imply a change in its state.
> I haven't really looked at the implications that would have elsewhere
> though - any thoughts?
>
>
The implications are huge... :-/
In 2002 we attempted to fix the lack of
const-correctness in the pipeline, and
the effects propagated all over the toolkit
to the point where we have to give up.
In order to fix the lack of const-correctness
in the pipeline your will have to rewrite the
pipeline from scratch.
Something that,
may or may not happen as part of ITKv4....
Cheers,
> Stu
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.itk.org/pipermail/insight-users/attachments/20100529/e9dbffbc/attachment.htm>
More information about the Insight-users
mailing list