Understanding basic example

I am trying to understand the following example:

Handle(V3d_Viewer) theViewer;
Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (theViewer);

BRepPrimAPI_MakeWedge aWedgeMaker (theWedgeDX, theWedgeDY, theWedgeDZ, theWedgeLtx);
TopoDS_Solid aShape = aWedgeMaker.Solid();

Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape); // creation of the presentable object
aContext->Display (aShapePrs, AIS_Shaded, 0, true);   // display the presentable object and redraw 3d viewer  

In particular, the line:

Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);

The signature of AIS_Shape constructor returns AIS_Shape class rather than Handle(AIS_Shape). Is there an operator or something going on?

I don't know C++ very well. I am just trying to create some binding for a different programming language.

Kirill Gavrilov's picture

Handle(AIS_Shape) is a smart-pointer to AIS_Shape (holding a raw pointer to AIS_Shape as a class field). The main purpose of smart-pointer is to delete the object once it is no used anymore and hence to avoid memory leaks. Object lifetime is managed by reference counter stored inside the object, incremented with each new copy of Handle(AIS_Shape) and decremented with each destruction of Handle(AIS_Shape) when it goes out of scope. Handle(T) is a preprocessor macros expanded to opencascade::handle<T> template class. It is similar to std::shared_ptr<T> template class from STL with some differences.

When you write

Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);

It can be expanded as (without compiler optimizations):

AIS_Shape* aShapePrsPtr = new AIS_Shape (aShape);
Handle(AIS_Shape) aShapePrs;
aShapePrs = aShapePrsPtr;

This works because Handle(AIS_Shape) class defines an assignment operator operator=(AIS_Shape*) capturing raw pointer into smart pointer. Note that in some other frameworks implementing smart pointers such assignment operator from raw pointer is considered dangerous (potential memory leaks / memory corruption on misuse) and disallowed, so that the only way to create smart pointer there is to pass it to smart pointer constructor or to dedicated method reset(T*). But Handle(T) has no such restriction due to slightly different design and usage approach, so that it could be initialized in both ways.

Jose M. Garcia's picture

Thanks a lot. This is exactly what I was looking for.

Jose M. Garcia's picture

Similar to my prior question:

Handle(V3d_Viewer) theViewer;
Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (theViewer);
aContext->Display (aShapePrs, AIS_Shaded, 0, true); 

Display is a method from AIS_InteractiveContext. But aContext is a Handle(AIS_InteractiveContext). As in my original question, what is going on under the hood to enable calling Display from aContext?

Kirill Gavrilov's picture

Smart pointers redefine operator->() and operator*() to return stored pointer, so that they behave like pointers (see Standard_Handle.hxx):

    //! Member access operator (note non-const)
    T* operator-> () const { return static_cast<T*>(this->entity); }

    //! Dereferencing operator (note non-const)
    T& operator* () const { return *get(); }