TKernel模块--自定义RTTI,对象句柄,引用计数

article/2025/6/24 13:43:05

TKernel模块–RTTI,对象句柄,引用计数

1.DEFINE_STANDARD_HANDLE(x1, x2)

#define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient)

其中:

#define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1; class Handle_##C1 : public Handle(C1) \
{ \
public: \Handle_##C1() {} \Handle_##C1(Handle(C1)&& theHandle) : Handle(C1)(theHandle) {} \template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> \inline Handle_##C1(const opencascade::handle<T2>& theOther) : Handle(C1)(theOther) {} \template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> \inline Handle_##C1(const T2* theOther) : Handle(C1)(theOther) {} \template<typename T> inline Handle_##C1& operator=(T theOther) { Handle(C1)::operator=(theOther); return *this; } \
};

也就是最终展开为:

class C1; 
class Handle_C1 : public Handle(C1) 
{
public:Handle_C1() {} Handle_C1(Handle(C1)&& theHandle) : Handle(C1)(theHandle) {}template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> inline Handle_C1(const opencascade::handle<T2>& theOther) : Handle(C1)(theOther) {} template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> inline Handle_C1(const T2* theOther) : Handle(C1)(theOther) {} template<typename T> inline Handle_C1& operator=(T theOther) { Handle(C1)::operator=(theOther); return *this; } 
};

实际上定义了一个新类型Handle_xxx,作为Handle(xxx)的另一种形态。

2.Handle(C1)

#define Handle(Class) opencascade::handle<Class>

其中:

namespace opencascade {template <class T>class handle {public:typedef T element_type;private:Standard_Transient* entity;private:void Assign (Standard_Transient *thePtr) {if (thePtr == entity)return;EndScope();// 递减先前对象引用entity = thePtr;BeginScope();// 增加新对象引用}void BeginScope() {if (entity != 0)entity->IncrementRefCounter();}void EndScope() {if (entity != 0 && entity->DecrementRefCounter() == 0)entity->Delete();entity = 0;}public:handle () : entity(0) {}handle (const T *thePtr) : entity(const_cast<T*>(thePtr)) {BeginScope();}handle (const handle& theHandle) : entity(theHandle.entity) {BeginScope();}handle (handle&& theHandle) Standard_Noexcept : entity(theHandle.entity) {theHandle.entity = 0;}~handle () {EndScope();}void Nullify() {EndScope();}bool IsNull() const { return entity == 0; } void reset (T* thePtr) {Assign (thePtr);}handle& operator= (const handle& theHandle) {Assign (theHandle.entity);return *this;}handle& operator= (const T* thePtr) {Assign (const_cast<T*>(thePtr));return *this;}handle& operator= (handle&& theHandle) Standard_Noexcept {std::swap (this->entity, theHandle.entity);// 指针交换。指针指向对象内部引用不变。return *this;}T* get() const { return static_cast<T*>(this->entity); }T* operator-> () const { return static_cast<T*>(this->entity); }T& operator* () const { return *get(); }template <class T2>bool operator== (const handle<T2>& theHandle) const { return get() == theHandle.get();}template <class T2>bool operator== (const T2 *thePtr) const { return get() == thePtr;}template <class T2>friend bool operator== (const T2 *left, const handle& right) {return left == right.get();}template <class T2>bool operator!= (const handle<T2>& theHandle) const {return get() != theHandle.get();}template <class T2>bool operator!= (const T2 *thePtr) const {return get() != thePtr;}template <class T2>friend bool operator!= (const T2 *left, const handle& right) {return left != right.get();}template <class T2>bool operator< (const handle<T2>& theHandle) const { return get() < theHandle.get();}/*作用:实现从handle<基类>到handle<派生类>的转换,通过dynamic_cast保证了转换的正确性。如果基类实际类型不是派生类或更具体类型,返回的handle<派生类>中指针为null。返回类型:使用 opencascade::std::enable_if 和 is_base_but_not_same 实现 SFINAE(Substitution Failure Is Not An Error),确保只有满足条件时才会编译此函数:is_base_but_not_same<T2, T>::value:检查 T2 是 T 的基类(但排除 T2 和 T 相同的情况)。若条件为真,返回 handle<T> 类型;否则忽略此函数(避免编译错误)*//*dynamic_cast<T*>:执行运行时类型检查(RTTI):若 theObject 实际指向的是 T 类型(或其派生类),返回正确的 T*。否则返回 nullptr(此时返回的 handle<T> 为空)。*/template <class T2>static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::typeDownCast (const handle<T2>& theObject) {return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));}template <class T2>static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type DownCast (const T2* thePtr) {return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));}explicit operator bool () const { return entity != nullptr;}template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>operator const handle<T2>& () const {return reinterpret_cast<const handle<T2>&>(*this);}/*作用:当T2是T的基类时,实现自动从handle<T>到handle<T2>的转换*/template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>operator handle<T2>& () {return reinterpret_cast<handle<T2>&>(*this);}template <class T2> friend class handle;};
} 

结合上述代码和注释不难理解handle,主要针对T为Standard_Transient派生类型时,提供自动引用管理及对原生指针的封装。

3.Standard_Transient

class Standard_Transient {
public:/*所有派生类需重复声明 DEFINE_STANDARD_ALLOC 以保持内存管理一致性。*//*DEFINE_STANDARD_ALLOC 在 Standard_Transient 中的作用是:1.替换默认内存管理,提升性能与安全性;2.为 OCCT 的引用计数和类型系统提供基础设施;3.确保跨平台行为一致。这是 OCCT 实现高性能、稳定性的核心设计之一。*/DEFINE_STANDARD_ALLOC
public:Standard_Transient() : myRefCount_(0) {}Standard_Transient (const Standard_Transient&) : myRefCount_(0) {}Standard_Transient& operator= (const Standard_Transient&) { return *this; }virtual ~Standard_Transient() {}
public: // 作为动态类型层次的起点。其base_type需要特殊指定。// 非起点一般用DEFINE_STANDARD_RTTIEXT,IMPLEMENT_STANDARD_RTTIEXT指定typedef void base_type;static constexpr const char* get_type_name () { return "Standard_Transient"; }// Standard_Type是自定义RTTI机制的实现者。Standard_Type类字段包含了自定义RTTI所需的信息。// 对Standard_Transient用于获得自身的RTTI注册及注册后结果。Standard_EXPORT static const opencascade::handle<Standard_Type>& get_type_descriptor (){return opencascade::type_instance<Standard_Transient>::get();}// 向RTTI注册并取得注册结果。Standard_EXPORT virtual const opencascade::handle<Standard_Type>& DynamicType() const{return get_type_descriptor();}Standard_EXPORT Standard_Boolean IsInstance(const opencascade::handle<Standard_Type>& theType) const{return (AType == DynamicType());}Standard_EXPORT Standard_Boolean IsInstance(const Standard_CString theTypeName) const{return IsEqual ( DynamicType()->Name(), theTypeName );}// 当aType就是Standard_Transient,或是Standard_Transient的某个父类时返回trueStandard_EXPORT Standard_Boolean IsKind(const opencascade::handle<Standard_Type>& aType) const{return DynamicType()->SubType ( aType );}Standard_EXPORT Standard_Boolean IsKind(const Standard_CString theTypeName) const{return DynamicType()->SubType ( theTypeName );}// 安全的取得自身指针Standard_EXPORT Standard_Transient* This() const{if (GetRefCount() == 0)throw Standard_ProgramError("Attempt to create handle to object created in stack, not yet constructed, or destroyed");return const_cast<Standard_Transient*> (this);}
public:inline Standard_Integer GetRefCount() const noexcept { return myRefCount_; }inline void IncrementRefCounter() noexcept {myRefCount_.operator++();}inline Standard_Integer DecrementRefCounter() noexcept {return myRefCount_.operator--();}// 释放自身virtual void Delete() const {delete this;}
private:std::atomic_int myRefCount_;
};

其中:

# define DEFINE_STANDARD_ALLOC                                         \void* operator new (size_t theSize)                                  \{                                                                    \return Standard::Allocate (theSize);                               \}                                                                    \void  operator delete (void* theAddress)                             \{                                                                    \Standard::Free (theAddress);                                       \}                                                                    \DEFINE_STANDARD_ALLOC_ARRAY                                          \DEFINE_STANDARD_ALLOC_PLACEMENT#  define DEFINE_STANDARD_ALLOC_ARRAY                                  \void* operator new[] (size_t theSize)                              \{                                                                  \return Standard::Allocate (theSize);                           \}                                                                  \void  operator delete[] (void* theAddress)                         \{                                                                  \Standard::Free (theAddress);                                   \}/*
DEFINE_STANDARD_ALLOC_PLACEMENT 是 OCCT 为高效内存管理提供的底层工具宏,通过自定义 placement new/delete 实现:
零开销对象构造:在预分配内存上直接初始化。
异常安全:满足 C++ 对 placement new 的配套要求。
与 OCCT 内存体系集成:服务于 Standard_Allocator 等模块。
这种设计在需要严格控制内存分配的 CAD/CAM 内核中尤为重要。
*/
#  define DEFINE_STANDARD_ALLOC_PLACEMENT                              \void* operator new (size_t, void* theAddress)                       \{                                                                   \return theAddress;                                                \}                                                                   \void operator delete (void*, void*)                                 \{                                                                   \}
/*
实例:
char* buffer = (char*)Standard::Allocate(sizeof(Geom_Point));
// 1.此语句会先触发placement new的执行。
// 2.基于placement new的返回值作为基础执行构造。
// 这就允许placement new实际返回另一个地址并在其上执行构造。不过默认实现里,返回传入地址。
Geom_Point* point = new (buffer) Geom_Point(0, 0, 0);  // 在 buffer 上构造对象
*/

Standard_Transient首先是OCCT中以引用计数管理自身的类层次起点,同时搭配OCCT中以Standard_Type为基础实现的自定义RTTI机制,提供相关服务。

由于类自定义了new/delete操作符,所以此类型实例的原始内存分配统一通过opencascade自定义方式进行。

4.Standard

class Standard {
public:DEFINE_STANDARD_ALLOCenum class AllocatorType {NATIVE = 0,OPT = 1,TBB = 2,JEMALLOC = 3};Standard_EXPORT static AllocatorType GetAllocatorType(){return allocatorTypeInstance();}/*以calloc为例:调用 C 标准库函数 calloc 分配一块大小为 theSize * sizeof(char) 的内存,并初始化为全零。使用实例:Standard_Address aPtr = calloc(1, sizeof(Geom_Point));Geom_Point* p = new (aPtr) Geom_Point(); // 在零初始化内存上构造对象*/Standard_EXPORT static Standard_Address Allocate (const Standard_Size theSize){#ifdef OCCT_MMGT_OPT_FLEXIBLEreturn Standard_MMgrFactory::GetMMgr()->Allocate(theSize);#elif defined OCCT_MMGT_OPT_JEMALLOCStandard_Address aPtr = je_calloc(theSize, sizeof(char));if (!aPtr)throw Standard_OutOfMemory("Standard_MMgrRaw::Allocate(): malloc failed");return aPtr;#elif defined OCCT_MMGT_OPT_TBBStandard_Address aPtr = scalable_calloc(theSize, sizeof(char));if (!aPtr)throw Standard_OutOfMemory("Standard_MMgrRaw::Allocate(): malloc failed");return aPtr;#elseStandard_Address aPtr = calloc(theSize, sizeof(char));if (!aPtr)throw Standard_OutOfMemory("Standard_MMgrRaw::Allocate(): malloc failed");return aPtr;#endif // OCCT_MMGT_OPT_FLEXIBLE}/*以malloc为例:优化体现在,相比calloc,malloc分配内存后无需初始化,有助于提升性能。*/Standard_EXPORT static Standard_Address AllocateOptimal (const Standard_Size theSize){#ifdef OCCT_MMGT_OPT_FLEXIBLEreturn Standard_MMgrFactory::GetMMgr()->Allocate(theSize);#elif defined OCCT_MMGT_OPT_JEMALLOCreturn je_malloc(theSize);#elif defined OCCT_MMGT_OPT_TBBreturn scalable_malloc(theSize);#elsereturn malloc(theSize);#endif}Standard_EXPORT static void Free (const Standard_Address thePtr){#ifdef OCCT_MMGT_OPT_FLEXIBLEStandard_MMgrFactory::GetMMgr()->Free(theStorage);#elif defined OCCT_MMGT_OPT_JEMALLOCje_free(theStorage);#elif defined OCCT_MMGT_OPT_TBBscalable_free(theStorage);#elsefree(theStorage);#endif}template <typename T>static inline void Free (T*& thePtr)  { Free ((void*)thePtr);thePtr = 0;}Standard_EXPORT static Standard_Address Reallocate (const Standard_Address theStorage, const Standard_Size theNewSize){#ifdef OCCT_MMGT_OPT_FLEXIBLEreturn Standard_MMgrFactory::GetMMgr()->Reallocate(theStorage, theSize);#elif defined OCCT_MMGT_OPT_JEMALLOCStandard_Address aNewStorage = (Standard_Address)je_realloc(theStorage, theSize);if (!aNewStorage)throw Standard_OutOfMemory("Standard_MMgrRaw::Reallocate(): realloc failed");return aNewStorage;#elif defined OCCT_MMGT_OPT_TBBStandard_Address aNewStorage = (Standard_Address)scalable_realloc(theStorage, theSize);if (!aNewStorage)throw Standard_OutOfMemory("Standard_MMgrRaw::Reallocate(): realloc failed");return aNewStorage;#elseStandard_Address aNewStorage = (Standard_Address)realloc(theStorage, theSize);if (!aNewStorage)throw Standard_OutOfMemory("Standard_MMgrRaw::Reallocate(): realloc failed");return aNewStorage;#endif}Standard_EXPORT static Standard_Address AllocateAligned (const Standard_Size theSize, const Standard_Size theAlign){#ifdef OCCT_MMGT_OPT_JEMALLOCreturn je_aligned_alloc(theAlign, theSize);#elif defined OCCT_MMGT_OPT_TBBreturn scalable_aligned_malloc(theSize, theAlign);#else#if defined(_MSC_VER)return _aligned_malloc(theSize, theAlign);#elif defined(__ANDROID__) || defined(__QNX__)return memalign(theAlign, theSize);#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && (defined(__i386) || defined(__x86_64)))/*作用:分配一块大小为 theSize 的内存,并确保其起始地址按 theAlign 字节对齐。*//*与标准 malloc 的区别特性	     _aligned_malloc				         标准 malloc对齐保证	强制按 theAlign 对齐			            通常仅 8/16 字节对齐释放方式	必须用 _aligned_free 释放	            直接用 free 释放跨平台性	Windows 特有(Linux 用 posix_memalign)	跨平台通用*/return _mm_malloc(theSize, theAlign);#elsevoid* aPtr;if (posix_memalign(&aPtr, theAlign, theSize)) {return NULL;}return aPtr;#endif#endif}Standard_EXPORT static void FreeAligned (const Standard_Address thePtrAligned){#ifdef OCCT_MMGT_OPT_JEMALLOCreturn je_free(thePtrAligned);#elif defined OCCT_MMGT_OPT_TBBreturn scalable_aligned_free(thePtrAligned);#else#if defined(_MSC_VER)_aligned_free(thePtrAligned);#elif defined(__ANDROID__) || defined(__QNX__)free(thePtrAligned);#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && (defined(__i386) || defined(__x86_64)))_mm_free(thePtrAligned);#elsefree(thePtrAligned);#endif#endif}template <typename T>static inline void FreeAligned (T*& thePtrAligned) {FreeAligned ((void* )thePtrAligned);thePtrAligned = 0;}Standard_EXPORT static Standard_Integer Purge(){#ifdef OCCT_MMGT_OPT_FLEXIBLEreturn Standard_MMgrFactory::GetMMgr()->Purge();#elsereturn true;#endif }
};

其中分配类型:

namespace {static Standard::AllocatorType& allocatorTypeInstance() {static Standard::AllocatorType aType =
#ifdef OCCT_MMGT_OPT_FLEXIBLEStandard::AllocatorType::NATIVE;
#elif defined OCCT_MMGT_OPT_TBBStandard::AllocatorType::TBB;
#elif defined OCCT_MMGT_OPT_JEMALLOCStandard::AllocatorType::JEMALLOC;
#elseStandard::AllocatorType::NATIVE;
#endifreturn aType;}
}

受到宏定义控制。

从上述代码中,可以看出Standard通过提供静态方法对外部提供统一的原始内存空间分配和回收,内部可以在编译时选择多种工作模式。

5.type_instance

namespace opencascade {template <typename T>class type_instance {static Handle(Standard_Type) myInstance;public:static const Handle(Standard_Type)& get ();};template <>class type_instance<void> {public:static Handle(Standard_Type) get () { return 0; }};template <typename T>const Handle(Standard_Type)& type_instance<T>::get () {static Handle(Standard_Type) anInstance = Standard_Type::Register (typeid(T), T::get_type_name(), sizeof(T), type_instance<typename T::base_type>::get());return anInstance;}
}

提供接口用于向自定义RTTI进行注册和获得注册结果。支持自定义RTTI机制的类其基类也需支持自定义RTTI机制。Standard_Transient是opencascade源码中支持自定义RTTI最开始的类型。

6.Standard_Type

class Standard_Type : public Standard_Transient {
public:// 返回类型对象的系统名称Standard_CString SystemName() const { return myInfo.name(); }// 返回类型对象的自定义名称Standard_CString Name() const { return myName; }// 返回类型对象实例占据的内存尺寸Standard_Size Size() const { return mySize; }// 用于返回当前类型的父类型(基类)信息/*使用实例:Handle(Standard_Type) currentType = STANDARD_TYPE(Geom2d_TrimmedCurve);while (!currentType.IsNull()) {std::cout << "Type: " << currentType->Name() << std::endl;currentType = currentType->Parent();  // 获取父类类型}*/const Handle(Standard_Type)& Parent () const { return myParent; }// 当theOther就是自身或自身的某个父类时返回trueStandard_EXPORT Standard_Boolean SubType (const Handle(Standard_Type)& theOther) const{return ! theOther.IsNull() && (theOther == this || (! myParent.IsNull() && myParent->SubType (theOther)));}// 当theOther就是自身或自身的某个父类时返回trueStandard_EXPORT Standard_Boolean SubType (const Standard_CString theOther) const{return theName != 0 && (IsEqual (myName, theName) || (! myParent.IsNull() && myParent->SubType (theName)));}/*首次调用时会完成注册行为*/template <class T>static const Handle(Standard_Type)& Instance() {return opencascade::type_instance<T>::get();}Standard_EXPORT static Standard_Type* Register (const std::type_info& theInfo, const char* theName, Standard_Size theSize, const Handle(Standard_Type)& theParent){static Standard_Mutex theMutex;Standard_Mutex::Sentry aSentry (theMutex);registry_type& aRegistry = GetRegistry();Standard_Type* aType = 0;auto anIter = aRegistry.find(theInfo);if (anIter != aRegistry.end())return anIter->second;aType = new Standard_Type (theInfo, theName, theSize, theParent);aRegistry.emplace(theInfo, aType);return aType;}Standard_EXPORT ~Standard_Type (){registry_type& aRegistry = GetRegistry();Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry",);}DEFINE_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)
private:Standard_Type (const std::type_info& theInfo, const char* theName, Standard_Size theSize, const Handle(Standard_Type)& theParent): myInfo(theInfo), myName(theName), mySize(theSize), myParent(theParent){}
private:std::type_index myInfo;         //!< Object to store system name of the classStandard_CString myName;        //!< Given name of the classStandard_Size mySize;           //!< Size of the class instance, in bytesHandle(Standard_Type) myParent; //!< Type descriptor of parent class
};

其中:

namespace {typedef std::unordered_map<std::type_index, Standard_Type*> registry_type;registry_type& GetRegistry()  {static registry_type theRegistry;return theRegistry;}
}

通过以上分析可知Standard_Type用于为向其注册的类型分配一个Standard_Type实例,用于实现此类型的自定义类型识别,通过注册方式为类型起名字,记录类型的父类信息。

7.DEFINE_STANDARD_RTTIEXT

#define DEFINE_STANDARD_RTTIEXT(Class,Base) \
public: \typedef Base base_type; \static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \Standard_EXPORT static const Handle(Standard_Type)& get_type_descriptor (); \Standard_EXPORT virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE;#define IMPLEMENT_STANDARD_RTTIEXT(Class,Base) \const Handle(Standard_Type)& Class::get_type_descriptor () { return Standard_Type::Instance<Class>(); } \const Handle(Standard_Type)& Class::DynamicType() const { return STANDARD_TYPE(Class); }#define STANDARD_TYPE(theType) theType::get_type_descriptor()

自定义类型通过在声明时加入DEFINE_STANDARD_RTTIEXT,在实现源代码文件中加入IMPLEMENT_STANDARD_RTTIEXT,即可提供向自定义RTTI机制注册并获得注册结果的接口,从而为该类型获得自定义RTTI机制的支持。

#define STANDARD_TYPE(theType) theType::get_type_descriptor()
#define DEFINE_STANDARD_RTTI_INLINE(Class,Base) \
public: \typedef Base base_type; \static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \static const Handle(Standard_Type)& get_type_descriptor () { return Standard_Type::Instance<Class>(); } \virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE { return get_type_descriptor (); }

DEFINE_STANDARD_RTTI_INLINE提供了无Standard_EXPORT的版本。STANDARD_TYPE用于快捷获得类型的Handle(Standard_Type),Standard_Type用于包含此类型的自定义RTTI信息。

8.DEFINE_STANDARD_ALLOC

#  define DEFINE_STANDARD_ALLOC_ARRAY                                  \void* operator new[] (size_t theSize)                               \{                                                                   \return Standard::Allocate (theSize);                              \}                                                                   \void  operator delete[] (void* theAddress)                          \{                                                                   \Standard::Free (theAddress);                                      \}#  define DEFINE_STANDARD_ALLOC_PLACEMENT                              \void* operator new (size_t, void* theAddress)                       \{                                                                   \return theAddress;                                                \}                                                                   \void operator delete (void*, void*)                                 \{                                                                   \}# define DEFINE_STANDARD_ALLOC                                         \void* operator new (size_t theSize)                                  \{                                                                    \return Standard::Allocate (theSize);                               \}                                                                    \void  operator delete (void* theAddress)                             \{                                                                    \Standard::Free (theAddress);                                       \}                                                                    \DEFINE_STANDARD_ALLOC_ARRAY                                          \DEFINE_STANDARD_ALLOC_PLACEMENT

DEFINE_STANDARD_ALLOC用于为自定义类型提供由opencascade提供的统一的内存分配机制。使得该类型的new/delete区别与c++中的默认行为。

1.Placement new 允许在已分配的内存地址上构造对象(不分配新内存,直接使用给定的指针 theAddress)。

意义

  • 用于内存池、自定义内存管理或需要精确控制对象内存位置的场景(如硬件寄存器映射)。
  • 通常与 new (address) ClassName() 语法配合使用。

2.placement delete

与 placement new 配对,用于在对象构造失败时释放资源(但实际极少使用)。

  • 如果 placement new 后的构造函数抛出异常,编译器会自动调用此版本的 operator delete 来清理。
  • 如果构造函数成功,此函数不会被调用(需手动调用析构函数,如 p->~ClassName())。

使用例子:

#include <stdio.h>
#include <iostream>
class A {
public:A() {printf("A()\n");}A(int ) {printf("A(int)\n");}~A() {printf("~A()\n");}void* operator new[] (size_t theSize) {        printf("new[]\n");return malloc (theSize); } void  operator delete[] (void* theAddress) {   printf("delete[]\n");free (theAddress);}void* operator new (size_t, void* theAddress) {    printf("placement new\n");return theAddress; } void operator delete (void*, void*) {    printf("placement delete\n");}void* operator new (size_t theSize) {printf("new\n");return malloc (theSize);} void  operator delete (void* theAddress) {        printf("delete\n");free (theAddress);   }};int main() {printf("hello world\n");A* lpA = new A();delete lpA;lpA = new A(10);delete lpA;char buffer[sizeof(A)];  A* p = new (buffer) A(); p->~A();               p = new (buffer) A(10);  p->~A();               int n;scanf_s("%d", &n);return 0;
}

在这里插入图片描述

这个例子中placement new/delete没啥实际作用,可用于new (buffer) A(xxx); 语法下额外执行此函数用于记录日志和统计。

9.DEFINE_NCOLLECTION_ALLOC

#  define DEFINE_NCOLLECTION_ALLOC                                               \void* operator new (size_t theSize,                                           \const Handle(NCollection_BaseAllocator)& theAllocator)    \{                                                                             \return theAllocator->Allocate(theSize);                                     \}                                                                             \void  operator delete (void* theAddress,                                      \const Handle(NCollection_BaseAllocator)& theAllocator) \{                                                                             \theAllocator->Free(theAddress);                                             \}

http://www.hkcw.cn/article/pnoiFZDdKb.shtml

相关文章

关于TongWeb数据源兼容mysql驱动的注意事项

问题现象&#xff1a; TongWeb数据源在采用mysql驱动的国产数据库时&#xff0c;因数据库慢报超时为数据源配置参数的 validation-query-timeout值5秒&#xff0c;而不是期望的maxwait、connectiontimeout值。 The last packet successfully received from the server was 5,0…

CSS专题之水平垂直居中

前言 石匠敲击石头的第 16 次 在日常开发中&#xff0c;经常会遇到水平垂直居中的布局&#xff0c;虽然现在基本上都用 Flex 可以轻松实现&#xff0c;但是在某些无法使用 Flex 的情况下&#xff0c;又应该如何让元素水平垂直居中呢&#xff1f;这也是一道面试的必考题&#xf…

(新)MQ高级-MQ的可靠性

消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消息丢失&#xff0c;所以MQ的可靠性也非常重要。 一、数据持久化 为了提升性能&#xff0c;默认情况下MQ的数据都是在内存存储的临时数据&#xff0c;重启后就会消失。为了保证数据的可靠性&#xff0c;必须…

Microsoft Word使用技巧分享(本科毕业论文版)

小铃铛最近终于完成了毕业答辩后空闲下来了&#xff0c;但是由于学校没有给出准确地参考模板&#xff0c;相信诸位朋友们也在调整排版时感到头疼&#xff0c;接下来小铃铛就自己使用到的一些排版技巧分享给大家。 注&#xff1a;以下某些设置是根据哈尔滨工业大学&#xff08;威…

Linux 基础IO(上)

目录 前言 重谈文件 文件操作 1.打开和关闭 2.对文件打开之后操作 理解文件fd 1.文件fd的分配规则与重定向 2.理解shell中的重定向 3.关于Linux下一切皆文件 关于缓冲区 1.为什么要有缓冲区 2.缓冲区刷新策略的问题 3.缓冲区的位置 前言 本篇到了我们linux中的文件…

单板机8088C语言计划

计划将原来用汇编写的小程序&#xff0c;用C语言重新写一遍 计划2个月能完成 然后再试试&#xff0c;能不能用C写一下固件BootLoad 和一个类似Dos时代的Debug调试器

C++11 语法特性一文详解

文章目录 1. C11 的发展史2. 列表初始化2.1 C98 中使用 {} 的初始化2.2 C11 中使用 {} 进行初始化2.3 std::initializer_list &#xff08;初始化列表&#xff09; 3. 右值引用与移动语义3.1 左值与右值3.1.1 右值分类 3.2 左值引用与右值引用3.2.1 const 左值引用为什么可以绑…

linux基础

参考视频 文章目录 1.网络的三种链接方式2. 目录结构详解3. 远程登陆和远程文件传输4. vi和vim4.1 vi和vim的三种模式4.2 vim快捷键 5. 关机重启和登录注销5.1 关机重启5.2 登录注销 6. 用户管理6.1 添加和删除用户6.2 用户信息6.3 用户组 7. 实用指令7.1 运行级别7.2 找回root…

【MLLM】多模态LLM 2025上半年技术发展(Better、Faster、Stronger)

note 文章目录 note一、新模型趋势任意模态模型推理模型小巧但功能强大的模型专家混合解码器视觉-语言-行动模型 VLA 二、特殊能力视觉语言模型中的目标检测、分割和计数多模态安全模型多模态RAG&#xff1a;检索器和重排器 三、多模态代理四、视频语言模型五、视觉语言模型的新…

python从零开始实现四极场离子轨迹仿真——框架

本篇将主要讲解程序的框架部分。 该程序主要分为三个部分&#xff0c;首先是初始化部分&#xff0c;主要为设置离子质荷比、初始位置、速度。 其次为求解轨迹部分&#xff0c;通过离子位置获取对应位置的电场&#xff0c;并经由空间电荷效应修改电场后&#xff0c;通过数值求解…

YOLO系列中的C3模块解析2025.5.31

YOLO系列中的 C3模块 是YOLOv5引入的核心组件之一&#xff0c;其设计目标是通过轻量化结构和高效特征提取提升模型性能。以下是C3模块的详细解析&#xff1a; 一、C3模块的网络层级结构 C3模块&#xff08;Cross Stage Partial Network with 3 convolutions&#xff09;结合了…

在Cesium中通过geojson和3d tiles分别加载楼宇白膜

一、geojson渲染楼宇白膜&#xff08;不推荐&#xff09; 如果你没有3dtiles文件来加载白膜&#xff0c;只有geojson加载白膜可以通过GeoJsonDataSource来加载白膜&#xff0c;json格式如下。 实现代码如下 <template><div id"cesium_container"></…

CRISPR-Cas系统的小型化研究进展-文献精读137

Progress in the miniaturization of CRISPR-Cas systems CRISPR-Cas系统的小型化研究进展 摘要 CRISPR-Cas基因编辑技术由于其简便性和高效性&#xff0c;已被广泛应用于生物学、医学、农学等领域的基础与应用研究。目前广泛使用的Cas核酸酶均具有较大的分子量&#xff08;通…

【Web API系列】WebTransportSendStream接口深度解析:构建高性能实时数据传输的基石

前言 随着Web应用复杂度的不断提升&#xff0c;传统的HTTP协议在某些场景下&#xff08;如实时游戏、视频流传输&#xff09;逐渐暴露出性能瓶颈。为解决这一问题&#xff0c;W3C提出了WebTransport API&#xff0c;旨在通过基于QUIC协议的低延迟、多路复用传输机制优化实时通…

MySQL中COUNT(*)、COUNT(1)和COUNT(字段名)的深度剖析与实战应用

MySQL中COUNT语句 三种COUNT函数的解析COUNT(*)COUNT(1)COUNT(字段名) 详细性能比较与实测分析性能差异的理论基础实际性能测试案例 实际案例解析案例1&#xff1a;电商平台订单统计案例2&#xff1a;带条件的计数比较案例3&#xff1a;性能优化实例 COUNT函数与索引的关系详解…

VS Code / Cursor 将默认终端设置为 CMD 完整指南

文章目录 &#x1f9ed; 适用范围&#x1f4cc; 背景与问题分析&#x1f6e0; 配置步骤1. 打开设置&#xff08;settings.json&#xff09;2. 添加或更新配置3. 重启终端与编辑器 &#x1f4a1; 补充&#xff1a;支持多个终端配置&#x1f9ef; 常见问题排查✅ 总结 在 Windows…

数据库高可用架构设计:集群、负载均衡与故障转移实践

关键词:数据库高可用,HA架构,数据库集群,负载均衡,故障转移,SQL Server Always On,MySQL InnoDB Cluster,高可用性组,读写分离,灾难恢复 在当今瞬息万变的数字化时代,数据的价值日益凸显,数据库作为承载核心业务数据的基石,其可用性直接决定了业务的连续性与用户…

【C#】一个简单的http服务器项目开发过程详解

这跟安装NoteJs程序运行脚本文件搭建一个简单Http服务器一样&#xff0c;相比起来&#xff0c;它的优点是可以开发的应用是免安装&#xff0c;跨平台的&#xff0c;放在移动盘上便捷的&#xff0c;这里着重讲http服务器实现的过程&#xff0c;以便自主实现特定的功能和服务。 …

谷歌:贝叶斯框架优化LLM推理反思

&#x1f4d6;标题&#xff1a;Beyond Markovian: Reflective Exploration via Bayes-Adaptive RL for LLM Reasoning &#x1f310;来源&#xff1a;arXiv, 2505.20561 &#x1f31f;摘要 通过强化学习 (RL) 训练的大型语言模型 (LLM) 表现出强大的推理能力和紧急反射行为&a…

C# 文件 I/O 操作详解:从基础到高级应用

在软件开发中&#xff0c;文件操作&#xff08;I/O&#xff09;是一项基本且重要的功能。无论是读取配置文件、存储用户数据&#xff0c;还是处理日志文件&#xff0c;C# 都提供了丰富的 API 来高效地进行文件读写操作。本文将全面介绍 C# 中的文件 I/O 操作&#xff0c;涵盖基…