c++parameter-passingpass-by-referenceitkreturn-by-reference

itk c++ function parameter passing


I am trying the simple act of writing a function (encapsulation) that calculates an histogram from the input via the itk ImageToHistogramFilter. While this works fine I do not seem to be able to get the result out of the function. My favourite approach for function parameters is passing by reference and return zero if succesfull:

int Histogram(HistogramType&result,ImageType const&image1,...
    auto f=HistogramFilterType::New();
    ...
    return EXIT_SUCCESS;

But now I have the absurd problem that I am not able to assign the result.

    std::cout<<"total frequency: "<<f->GetOutput()->GetTotalFrequency()<<std::endl;//This gives a reasonable value like 2334;
    result=*(f->GetOutput());

This does not work because it was deleted:

/usr/local/include/ITK-5.3/itkHistogram.h:80:3: note: declared here
   80 |   ITK_DISALLOW_COPY_AND_MOVE(Histogram);

I tried to do it the way chosen in the docs:

int Histogram(HistogramType::Pointer result,ImageType::ConstPointer image1,...
    auto f=HistogramFilterType::New();
    ...
    std::cout<<"total frequency: "<<f->GetOutput()->GetTotalFrequency()<<std::endl;//This still gives a reasonable value like 2334;
    result=f->GetOutput();

    std::cout<<"total frequency: "<<rslt->GetOutput()->GetTotalFrequency()<<std::endl;//This too gives a reasonable value like 2334;
    ...
    return EXIT_SUCCESS;

This does compile now, however when I try to access the result (outside of the function scope), the object pointed seems to be lost though it shall be a smart pointer:

auto result=HistogramType::New();
if(Histogram(result,aVariableWithAnImage...
    return EXIT_FAILURE;
else
    std::cout<<result->GetTotalFrequency()<<std::endl;//This gives 0 now

I tried other variations with the itk object functions Clone() and get() to bypass the disallow but of course (or luckily I must admit) it did not work. I feel I am doing something fundamentally wrong.


Solution

  • Send the parameter through reference like this:

    int Histogram(HistogramType** result, ImageType::ConstPointer image1,...)
    {
      auto f=HistogramFilterType::New();
      ...
      std::cout<<"total frequency: "<<f->GetOutput()->GetTotalFrequency()<<std::endl;//This still gives a reasonable value like 2334;
      *result = f->GetOutput();
    
      std::cout<<"total frequency: "<<rslt->GetOutput()->GetTotalFrequency()<<std::endl;//This too gives a reasonable value like 2334;
      ...
      return EXIT_SUCCESS;
    }
    

    The parameter HistogramType** result is a pointer to pointer to HistogramType because it looks like the variable you want to return is f->GetOutput(), a pointer to HistogramType.

    Then you will use the function like this:

    HistogramType* result = NULL;
    if(Histogram(&result, aVariableWithAnImage...)
        return EXIT_FAILURE;
    else
        std::cout<<result->GetTotalFrequency()<<std::endl; //This should print the right value now
    

    In this way you return f->GetOutput() from your function into the result variable outside of your function.

    What you did in the first example was to pass by reference a HistogramType, and in the function use the operator= of HistogramType, which I am not sure what it does for your class, it probably needs a deep copy override to make this work.

    Edit: What happens in your second attempt with the smart pointer is that you send the object (auto result=HistogramType::New()) as value to a parameter of type smart pointer. The compiler does an implicit cast by calling the smart pointer constructor with your variable result as parameter. The result is that in the function you have a smart pointer parameter passed as value referring to your result variable. Within the function scope it works by replacing the referred object from result to f->GetOutput(), but the outside variable result never gets changed. You can make this variant work as well, if you define the outside variable result as smart pointer, then pass it as reference (int Histogram(HistogramType::Pointer& result,...).