You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
7.7 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkGarbageCollector.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @class vtkGarbageCollector
* @brief Detect and break reference loops
*
* vtkGarbageCollector is used by VTK classes that may be involved in
* reference counting loops (such as Algorithm <-> Executive). It
* detects strongly connected components of the reference graph that
* have been leaked deletes them. The garbage collector uses the
* ReportReferences method to search the reference graph and construct
* a net reference count for each connected component. If the net
* reference count is zero the entire set of objects is deleted.
* Deleting each component may leak other components, which are then
* collected recursively.
*
* To enable garbage collection for a class, add these members:
*
* \code
*
* public:
* void Register(vtkObjectBase* o) override
* {
* this->RegisterInternal(o, true);
* }
* void UnRegister(vtkObjectBase* o) override
* {
* this->UnRegisterInternal(o, true);
* }
*
* protected:
*
* void ReportReferences(vtkGarbageCollector* collector) override
* {
* // Report references held by this object that may be in a loop.
* this->Superclass::ReportReferences(collector);
* vtkGarbageCollectorReport(collector, this->OtherObject, "Other Object");
* }
* \endcode
*
* The implementations should be in the .cxx file in practice.
* It is important that the reference be reported using the real
* pointer or smart pointer instance that holds the reference. When
* collecting the garbage collector will actually set this pointer to
* nullptr. The destructor of the class should be written to deal with
* this. It is also expected that an invariant is maintained for any
* reference that is reported. The variable holding the reference
* must always either be nullptr or refer to a fully constructed valid
* object. Therefore code like "this->Object->UnRegister(this)" must
* be avoided if "this->Object" is a reported reference because it
* is possible that the object is deleted before UnRegister returns
* but then "this->Object" will be left as a dangling pointer. Instead
* use code like
*
* \code
* vtkObjectBase* obj = this->Object;
* this->Object = 0;
* obj->UnRegister(this);
* \endcode
*
* so that the reported reference maintains the invariant.
*
* If subclassing from a class that already supports garbage
* collection, one need only provide the ReportReferences method.
*/
#ifndef vtkGarbageCollector_h
#define vtkGarbageCollector_h
#include "vtkCommonCoreModule.h" // For export macro
#include "vtkGarbageCollectorManager.h" // Needed for singleton initialization.
#include "vtkObject.h"
// This function is a friend of the collector so that it can call the
// internal report method.
void VTKCOMMONCORE_EXPORT vtkGarbageCollectorReportInternal(
vtkGarbageCollector*, vtkObjectBase*, void*, const char*);
// This allows vtkObjectBase to get at the methods it needs.
class vtkObjectBaseToGarbageCollectorFriendship;
class VTKCOMMONCORE_EXPORT vtkGarbageCollector : public vtkObject
{
public:
vtkTypeMacro(vtkGarbageCollector, vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) override;
static vtkGarbageCollector* New();
/**
* Collect immediately using any objects whose collection was
* previously deferred as a root for the reference graph walk.
* Strongly connected components in the reference graph are
* identified. Those with a net reference count of zero are
* deleted. When a component is deleted it may remove references to
* other components that are not part of the same reference loop but
* are held by objects in the original component. These removed
* references are handled as any other and their corresponding
* checks may be deferred. This method keeps collecting until no
* deferred collection checks remain.
*/
static void Collect();
/**
* Collect immediately using the given object as the root for a
* reference graph walk. Strongly connected components in the
* reference graph are identified. Those with a net reference count
* of zero are deleted. When a component is deleted it may remove
* references to other components that are not part of the same
* reference loop but are held by objects in the original component.
* These removed references are handled as any other and their
* corresponding checks may be deferred. This method does continue
* collecting in this case.
*/
static void Collect(vtkObjectBase* root);
//@{
/**
* Push/Pop whether to do deferred collection. Whenever the total
* number of pushes exceeds the total number of pops collection will
* be deferred. Code can call the Collect method directly to force
* collection.
*/
static void DeferredCollectionPush();
static void DeferredCollectionPop();
//@}
//@{
/**
* Set/Get global garbage collection debugging flag. When set to true,
* all garbage collection checks will produce debugging information.
*/
static void SetGlobalDebugFlag(bool flag);
static bool GetGlobalDebugFlag();
//@}
protected:
vtkGarbageCollector();
~vtkGarbageCollector() override;
private:
/**
* Called by UnRegister method of an object that supports garbage
* collection. The UnRegister may not actually decrement the
* reference count, but instead hands the reference to the garbage
* collector. If a reference can be given, this method accepts it
* from the caller by returning 1. If the reference cannot be
* accepted then it returns 0. This may be the case when delayed
* garbage collection is disabled, or when the collector has decided
* it is time to do a check.
*/
static int GiveReference(vtkObjectBase* obj);
/**
* Called by Register method of an object that supports garbage
* collection. The Register may not actually increment the
* reference count if it can take a reference previously handed to
* the garbage collector. If a reference can be taken, this method
* hands it back to the caller by returning 1. If no reference is
* available, returns 0.
*/
static int TakeReference(vtkObjectBase* obj);
// Singleton management functions.
static void ClassInitialize();
static void ClassFinalize();
friend class vtkGarbageCollectorManager;
friend class vtkObjectBaseToGarbageCollectorFriendship;
// Internal report callback and friend function that calls it.
virtual void Report(vtkObjectBase* obj, void* ptr, const char* desc);
friend void VTKCOMMONCORE_EXPORT vtkGarbageCollectorReportInternal(
vtkGarbageCollector*, vtkObjectBase*, void*, const char*);
private:
vtkGarbageCollector(const vtkGarbageCollector&) = delete;
void operator=(const vtkGarbageCollector&) = delete;
};
class vtkSmartPointerBase;
/**
* Function to report a reference held by a smart pointer to a collector.
*/
void VTKCOMMONCORE_EXPORT vtkGarbageCollectorReport(
vtkGarbageCollector* collector, vtkSmartPointerBase& ptr, const char* desc);
/**
* Function to report a reference held by a raw pointer to a collector.
*/
template <class T>
void vtkGarbageCollectorReport(vtkGarbageCollector* collector, T*& ptr, const char* desc)
{
vtkGarbageCollectorReportInternal(collector, ptr, &ptr, desc);
}
#endif
// VTK-HeaderTest-Exclude: vtkGarbageCollector.h