[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