I use a monitoring class Progress. In a lot of functions, I update the progress if given. The progress variable is optional and given by pointer that could be null. A lot of part of my code look like this:
void do_the_job(Progress* progress)
{
do_part_1();
if((bool)progress)
progress->set(0.25f);
do_part_2();
if((bool)progress)
progress->set(1.0f);
}
Before creating it myself, I'm looking for a kind of smart pointer checking for me if it's null and ignoring the call if null. Somthing that could be used like this:
void do_the_job(boost::could_be_null_ptr<Progress> progress)
{
do_part_1();
progress->set(0.25f); // ignored if null
do_part_2();
progress->set(1.0f); // ignored if null
}
For compatibility reason, I don't use C++11 or >C++11. Please, only solutions working with C++03.
The function should not have to bother with a null pointer so design the Progress such that it can be used like this:
void do_the_job(XProgress& progress)
{
do_part_1();
progress.set(0.25f);
do_part_2();
progress.set(1.0f);
}
Getting there is simple:
struct XProgress {
std::shared_ptr<Progress> instance;
void set(float x) {
if (instance) instance->set(x);
}
};
In any case you need some instance on which you can call set, so there is no way to avoid reimplementing Progesss interface.
Sorry, missed the "only C++03". If you cannot use shared_ptr use the memory mangagment mechanism of your chioce. Perhaps a raw pointer that gets deleted in XProgress destructor is fine if you disable copying.
I am currently using the dlopen functions for some plugin project.
This function handle returns a void* and then I save all the handle to a map named handles:
void* handle = dlopen(path.c_str(), RTLD_LAZY);
handles[file] = handle;
My goal is to pass the ownership to the map, I was thinking of a unique_ptr, but not sure if this is even possible.
If it's not possible what other alternatives do I have ?
If I understand correctly you can do something like
Define a close function and an alias for the pointer type:
auto closeFunc = [](void* vp) {
dlclose(vp);
};
using HandlePtr = std::unique_ptr<void, decltype(closeFunc)>;
std::map<std::string, HandlePtr> handles;
and then create the handles and add to the map:
void* handle = dlopen(path.c_str(), RTLD_LAZY);
HandlePtr ptr( handle, closeFunc );
handles[file] = std::move( ptr );
Then closeFunc will be called when the unique ptr goes out of scope
The raw pointer can be prevented by combining the two lines above:
HandlePtr handle(dlopen(path.c_str(), RTLD_LAZY), closeFunc );
handles[file] = std::move( handle );
This makes use of the second argument to the std::unique_ptr that specifies the deleter to use.
PS: maps and unique_ptrs don't play well as-is, you might need some emplaces or moves depending on the C++ standard you are using. Or use shared_ptr instead.
Even if TheBadger answer's is the best to follow. Remember that there is no concept of ownership in C++, C++ provides classes to simulate this and make a good use of RAII, but you don't really have any guarantees from the language to assure a ressource's ownership, even with unique_ptr, for example :
{
auto p_i = new int{5};
auto up_i = std::unique_ptr<int>{p_i};
*p_i = 6; //nothing in the language prevent something like this
assert(*up_i == 6); //the unique_ptr ownership is not assured as you can see here
delete p_i; //still not illegal
} //at run time, RAII mechanism strikes, destroy unique_ptr, try to free an already freed memory, ending up to a core dumped
You even have a get member function in unique_ptr class that gives you the opportunity to mess up your memory as you could with raw pointers.
In C++, there's no mechanism to detect "ownership" violation at compile time, maybe you can find some tools out there to check it but it's not in the standard, but it's only a matter of recommended practices.
Thus, it's more relevant and precise to talk about "managed" memory in C++ instead of "ownership".
The std::unique_ptr is particularly useful for "wrapping" c-libraries that operate using a resource than needs deleting or closing when finished. Not only does it stop you forgetting when to delete/close the resource it also make using the resource exception safe - because the resource gets properly cleaned up in the event of an exception.
I would probably do something like this:
// closer function to clean up the resource
struct dl_closer{ void operator()(void* dl) const { dlclose(dl); }};
// type alias so you don't forget to include the closer functor
using unique_dl_ptr = std::unique_ptr<void, dl_closer>;
// helper function that ensures you get a valid dl handle
// or an exception.
unique_dl_ptr make_unique_dl(std::string const& file_name)
{
auto ptr = unique_dl_ptr(dlopen(file_name.c_str(), RTLD_LAZY));
if(!ptr)
throw std::runtime_error(dlerror());
return ptr;
}
And use it a bit like this:
// open a dl
auto dl_ptr = make_unique_dl("/path/to/my/plugin/library.so");
// now set your symbols using POSIX recommended casting gymnastics
void (*my_function_name)();
if(!(*(void**)&my_function_name = dlsym(dl_ptr.get(), "my_function_name")))
throw std::runtime_error(dlerror());
I open a MSI database view using MsiDatabaseOpenView followed by a call to MsiViewExecute. Then do I need to call MsiViewClose even if I do make a call to MsiCloseHandle? Will MsiCloseHandle not call MsiViewClose (or do something to close all required handles internally)?
The actual reason why I'm asking this:
There is a class PMSIHANDLE which is recommended instead of manually closing the handles (destructor will call MsiCloseHandle - source code visible in VS). So when I open the view using MsiDatabaseOpenView and wrap the handle in PMSIHANDLE, I am relieved from calling MsiCloseHandle, but I must(?) call MsiViewClose!?
Answer
MsiViewClose() is not required to close the handle. It is only required, if you want to run MsiViewExecute() on the same view again, which can be useful to pass different parameters to a parameterized SQL query. This is stated in the remarks of the documentation:
The MsiViewClose function must be called before the MsiViewExecute
function is called again on the view, unless all rows of the result
set have been obtained with the MsiViewFetch function.
In the most common use case, where you only do a single MsiViewExecute() call for a given view, you don't need to call MsiViewClose():
PMSIHANDLE pView;
UINT res = MsiDatabaseOpenViewW( hDatabase, L"SELECT * FROM `File`", &pView );
if( res == ERROR_SUCCESS )
{
res = MsiViewExecute( pView, nullptr );
}
// Destructor of PMSIHANDLE calls MsiCloseHandle()
Side Notes
From a modern C++ point of view, PMSIHANDLE appears to be badly designed. For one, it provides no protection against accidentally copying of a handle, which would result in calling MsiViewClose() twice on the same handle. Also while the implicit conversion to MSIHANDLE* can be convenient, it is also dangerous because it makes it possible to accidentally overwrite an existing handle, without closing it first.
Here is an alternative to PMSIHANDLE based on C++11s std::unique_ptr:
// A deleter for MSIHANDLE.
struct MsiHandleDeleter
{
// This alias enables us to actually store values of type MSIHANDLE in the unique_ptr
// (by default it would be MSIHANDLE*).
using pointer = MSIHANDLE;
void operator()( MSIHANDLE h ) const { if( h ) ::MsiCloseHandle( h ); }
};
// A RAII wrapper for MSI handle. The destructor automatically closes the handle, if not 0.
using UniqueMsiHandle = std::unique_ptr< MSIHANDLE, MsiHandleDeleter >;
Usage example:
UniqueMsiHandle record{ ::MsiCreateRecord( 1 ) };
::MsiRecordSetInteger( record.get(), 1, 42 );
// Destructor takes care of calling MsiCloseHandle(), just like PMSIHANDLE.
Compared to PMSIHANDLE it's more cumbersome to use it with functions that have MSIHANDLE* out parameters, but this can easily be remedied by creating wrapper functions or classes that work with UnqiueMsiHandle.
Advantages:
Less ways to do things wrong.
Clear ownership and moveability.
Everyone who is used to std::unique_ptr will immediately understand the semantics of UniqueMsiHandle.
Is it possible to create a shared_ptr to an *anonymous struct? *I'm not quite sure if the struct below constitutes an anonymous struct. For example;
struct { HWND hwnd; } *tmpArgs;
tmpArgs->hwnd = hwnd;
std::shared_ptr<struct> evtArgs(tmpArgs); // possible? right now its a compile error "'struct': missing tag name"
// usage
evtHandler( evtArgs ); // evtHandler( std::weak_ptr<void> EventArguments );
I have a very narrow/specialised case where I need to pass a structure tmpArgs that is not going to be used anywhere else in the application. So I dont need to declare a new struct type.
You can get the shared_ptr you crave...
std::shared_ptr<std::remove_pointer<decltype(tmpArgs)>::type> evtArgs(tmpArgs);
but you're not going to be able to pass it out of the scope of this code in any useful way.
Potentially, this would be useful if you're trying to ensure that the class is only ever referenced via the shared_ptr or a weak_ptr, and so you're putting this stuff at namespace scope. But that seems a stretch away from good coding style to me.
I am writing a library in C++, but want it to have a C API, which should also be thread safe. One thing that the API needs to do is to pass back and forth handles (e.g. a structure containing a reference or pointer) of objects created within the library. These objects need to be destroyed at some point, so any handles to such an object that were still in existence would them become invalid.
EDIT: We cannot assume that each handle is only used within a single client thread. In particular I want to handle the case where there are two client threads accessing the same resource simultaneously, one trying to destroy it while the other tries to modify it
There are two paradigms for dealing with this. One is the smart pointer paradigm, for example boost::shared_ptr or std::shared_ptr, which make sure the object is only destroyed when there are no more references to it. However, as I understand it, such pointers aren't possible to implement in C (as it doesn't support constructors and destructors), so this approach won't work in my case. I don't want to rely on the user to call a "release" function for every instance of a handle they obtain, since they inevitably won't.
Another paradigm is to simply destroy the object within the library, and have any subsequent function calls which pass a handle to that object as an input simply return an error code. My question is what techniques or libraries are available to implement this approach, specifically in a multi-threaded application?
EDIT:
The library should of course handle all the allocation of deallocation of internal memory itself. Smart pointers may be also used within the library; they may not be passed across the API, however.
EDIT:
More detail on handles might be used on the client side: the client might have two threads, one of which creates an object. That thread might pass the handle to the second thread, or the second thread might get it from the library using a "find_object" function. The second thread might then continuously update the object, but while that is going on the first thread might destroy the object, making all handles to the object invalid.
I appreciate rough suggestions of an approach - I have come up with some of these myself too. However, the nitty gritty details of things like how a C++ class instance is retrieved and locked, given a handle, while other threads may be attempting to destroy that object, are non-trivial, so I'm really after answers like "I have done the following and it works without fail." or, even better, "This library implements what you're after sensibly and safely".
IMHO handles (e.g. simple integer numbers) that are kept as key values in a map of smart pointers internally might be a viable solution.
Though you'll need to have a mechanism that guarantees a handle that was freed by a particular client won't destroy the map entry, as long the handle is still used by other clients in a multithreaded environment.
UPDATE:
At least #user1610015 answer isn't such a bad idea (if you're working with a COM enabled environment). In any case you'll need to keep track with some reference counting of your internally managed class instances.
I'm not so experienced with the C++11 or boosts smart pointer features, and how it's possible to intercept or override reference counting mechanism with these. But e.g. Alexandrescou's loki library smart pointer considerations may let you implement an appropriate policy on how you're going to handle the reference counting and which interfaces can access this or not.
It should be possible with Alexandrescou's Smart Pointer to provide a ref counting mechanism that supports access via a C-API and C++ internal implementation concurrently and thread safe.
One thing that the API needs to do is to pass back and forth handles
Ok so far
(e.g. a structure containing a reference or pointer)
Why? A "handle" is just a way to identify an object. Doesn't necessarily mean it has to hold the reference or pointer.
One is the smart pointer paradigm, for example boost::shared_ptr or std::shared_ptr, which make sure the object is only destroyed when there are no more references to it.
Sure, a
map<int, boost::shared_ptr<my_object>>
might work fine here if you want to use it for your memory deallocation mechanism.
simply destroy the object within the library,
This can exist with smart pointers, its not one or the other.
have any subsequent function calls which pass a handle to that object as an input simply return an error code.
sure sounds good.
If your library is responsible for allocating memory, then it should be responsible for deallocating memory.
I would return simple integer "handles" from the library _GetNewObject() method.
Your library needs a map of handles to internal objects. No one outside the library should see the objects from the C interface.
All the library methods should take a handle as their first parameter.
For the multi-threaded stuff, do two threads need to access the same object? If so, you'll need to put in some sort of locking that occurs when a C API function is entered, and released before it leaves. You will have to make a decision if you want the code outside the library to know about this locking (you probably don't), a C function that calls the library function will probably just want to get the return value and not worry about the lock/unlock.
So your library needs:
an interface to allocate and deallocate objects, viewed as handles by the outside
an interface to do stuff given the handles.
EDIT: MORE INFO
Within the library I would use a Factory pattern to create new objects. The Factory should hand out a shared_ptr after the object allocation. This way everything else in the library just uses shared_ptr, and the cleanup will be fairly automatic (i.e. the factory doesn't have to store a list of what is created to remember to clean up, and no one has to call delete explicitly). Store the shared_ptr in the map with the handle. You'll probably need some sort of static counter along with a GetNextHandle() function to get the next available handle and to deal with wrap around (depending on how many objects are created and destroyed within the lifetime of the running program).
Next, put your shared pointer into a Proxy. The proxy should be very lightweight and you can have many Proxy objects per actual object. Each proxy will hold a private shared_ptr and whatever thread / mutex object you choose to use (you haven't given any information about this, so its hard to be any more specific). When a Proxy is created, it should acquire the mutex, and release on destruction (i.e. RAII for releasing the lock).
You haven't included any information on how to determine if you want to create a new object or find an existing object, and how two different threads would "find" the same object. However, lets assume that you have a GetObject() with enough parameters to uniquely identify each object and return the handle from the map, if the objects exists.
In this case, each of your visible extern C library functions would accept an object handle and:
Create a new Proxy for the given handle. In the Proxy constructor, the Proxy would look in the map to find the handle, if it doesn't exist, ask the Factory to create one (or return an error, your choice here). The Proxy would then acquire the lock. Your function would then get the pointer from the Proxy and use it. When the function exits, the Proxy goes out of scope, releases the lock, and decrements the reference counter.
If two functions are running in different threads, as long as a Proxy exists in one of the functions, the object will still exist. The other function could ask the library to delete the object which would remove the reference from the map. Once all the other functions with active Proxy objects finish, the final shared_ptr will go out of scope and the object will be deleted.
You can do most of this generically with templates, or write concrete classes.
EDIT: MORE INFO
The Proxy will be a small class. It will have a shared_ptr, and have a lock. You would instantiate a Proxy within the scope of the extern C function called by the client (note, this is actually a C++ function with all the benefits such as being able to use C++ classes). The proxy is small and should go on the stack (do not new and delete this, more trouble than its worth, just make a scoped variable and let C++ do the work for you). The proxy would use the RAII pattern to get a copy of the shared_ptr (which would increment the reference count of the shared_ptr) and acquire the lock at construction. When the Proxy goes out of scope, the shared_ptr it has is destroyed thus decrementing the reference count. The Proxy destructor should release the lock. BTW, you may want to think about blocking and how you want your thread mutexes to work. I don't know enough about your specific mutex implementation to suggest anything yet.
The map will contain the "master" shared_ptr that all others are copied from. However, this is flexible and decoupled because once a Proxy gets a shared_ptr from the map, it doesn't have to worry about "giving it back". The shared_ptr in the map can be removed (i.e. the object no longer "exists" to the Factory), but there can still be Proxy classes that have a shared_ptr, so the actual object will still exist as long as something is using it.
When code uses handles, it is almost always responsible for calling a dispose handle function. And operating on a disposed handle is then illegal.
Handles are usually either pointers to forward decl struct with no body, or pointers to structwith a preable field or two (maybe to help debugging on the C side) that are incomplete. Creation and destruction of them occur inside the API.
In the API you have a full view ofthe contents of the handle, which need not be a C struct -- it can have unique ptrs or whatever. You will have to delete the handle manually, but that is inevidable.
As noted below, another possible handle is a guid, with inside the API having a map from guid to data. This is slow, but the space of guids is practically infinite, so you can detect use of erased handles and return an error. Note that failure to return a handle leaks the resource, but this eliminates dangling pointer segfaults at a modsst runtime cost.
Another way is to expose a COM API. This has the benefit that it's object-oriented, unlike a C API. But it still can be used from C. It would look like this:
C++:
// Instantiation:
ISomeObject* pObject;
HRESULT hr = CoCreateInstance(..., IID_PPV_ARGS(&pObject));
// Use:
hr = pObject->SomeMethod(...);
// Cleanup:
pObject->Release();
C:
// Instantiation:
ISomeObject* pObject;
HRESULT hr = CoCreateInstance(..., IID_PPV_ARGS(&pObject));
// Use:
hr = (*pObject->lpVtbl->SomeMethod)(pObject, ...);
// Cleanup:
(*pObject->lpVtbl->Release)(pObject);
Also, if the client is C++, it can use a COM smart pointer like ATL's CComPtr to automate memory management. So the C++ code could be turned into:
// Instantiation:
CComPtr<ISomeObject> pSomeObject;
HRESULT hr = pSomeObject.CoCreateInstance(...);
// Use:
hr = pSomeObject->SomeMethod(...);
// Cleanup is done automatically at the end of the current scope
Perhaps I have too much time on my hands... but I've thought about this a few times and decided to just go ahead and implement it. C++ calleable, no external libs. Totally reinvented the wheel, just for fun (if you can call coding on a sunday fun.)
Note, synchronization is not here, because I don't know what OS you are on...
SmartPointers.h:
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __cplusplus
#define bool int
#define true (1 == 1)
#define false (1 == 0)
#endif
// Forward declarations
struct tSmartPtr;
typedef struct tSmartPtr SmartPtr;
struct tSmartPtrRef;
typedef struct tSmartPtrRef SmartPtrRef;
// Type used to describe the object referenced.
typedef void * RefObjectPtr;
// Type used to describe the object that owns a reference.
typedef void * OwnerPtr;
// "Virtual" destructor, called when all references are freed.
typedef void (*ObjectDestructorFunctionPtr)(RefObjectPtr pObjectToDestruct);
// Create a smart pointer to the object pObjectToReference, and pass a destructor that knows how to delete the object.
SmartPtr *SmartPtrCreate( RefObjectPtr pObjectToReference, ObjectDestructorFunctionPtr Destructor );
// Make a new reference to the object, pass in a pointer to the object that will own the reference. Returns a new object reference.
SmartPtrRef *SmartPtrMakeRef( SmartPtr *pSmartPtr, OwnerPtr pReferenceOwner );
// Remove a reference to an object, pass in a pointer to the object that owns the reference. If the last reference is removed, the object destructor is called.
bool SmartPtrRemoveRef( SmartPtr *pSmartPtr, OwnerPtr pReferenceOwner );
// Remove a reference via a pointer to the smart reference itself.
// Calls the destructor if all references are removed.
// Does SmartPtrRemoveRef() using internal pointers, so call either this or SmartPtrRemoveRef(), not both.
bool SmartPtrRefRemoveRef( SmartPtrRef *pRef );
// Get the pointer to the object that the SmartPointer points to.
void *SmartPtrRefGetObjectPtr( SmartPtrRef *pRef );
#ifdef __cplusplus
}
#endif
#endif // #ifndef SMARTPOINTER_H
SmartPointers.c:
#include "SmartPointers.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
typedef struct tLinkedListNode {
struct tLinkedListNode *pNext;
} LinkedListNode;
typedef struct tLinkedList {
LinkedListNode dummyNode;
} LinkedList;
struct tSmartPtrRef {
LinkedListNode listNode;
OwnerPtr pReferenceOwner;
RefObjectPtr pObjectReferenced;
struct tSmartPtr *pSmartPtr;
};
struct tSmartPtr {
OwnerPtr pObjectRef;
ObjectDestructorFunctionPtr ObjectDestructorFnPtr;
LinkedList refList;
};
// Initialize singly linked list
static void LinkedListInit( LinkedList *pList )
{
pList->dummyNode.pNext = &pList->dummyNode;
}
// Add a node to the list
static void LinkedListAddNode( LinkedList *pList, LinkedListNode *pNode )
{
pNode->pNext = pList->dummyNode.pNext;
pList->dummyNode.pNext = pNode;
}
// Remove a node from the list
static bool LinkedListRemoveNode( LinkedList *pList, LinkedListNode *pNode )
{
bool removed = false;
LinkedListNode *pPrev = &pList->dummyNode;
while (pPrev->pNext != &pList->dummyNode) {
if (pPrev->pNext == pNode) {
pPrev->pNext = pNode->pNext;
removed = true;
break;
}
pPrev = pPrev->pNext;
}
return removed;
}
// Return true if list is empty.
static bool LinkedListIsEmpty( LinkedList *pList )
{
return (pList->dummyNode.pNext == &pList->dummyNode);
}
// Find a reference by pReferenceOwner
static SmartPtrRef * SmartPtrFindRef( SmartPtr *pSmartPtr, OwnerPtr pReferenceOwner )
{
SmartPtrRef *pFoundNode = NULL;
LinkedList * const pList = &pSmartPtr->refList;
LinkedListNode *pIter = pList->dummyNode.pNext;
while ((pIter != &pList->dummyNode) && (NULL == pFoundNode)) {
SmartPtrRef *pCmpNode = (SmartPtrRef *)pIter;
if (pCmpNode->pReferenceOwner == pReferenceOwner) {
pFoundNode = pCmpNode;
}
pIter = pIter->pNext;
}
return pFoundNode;
}
// Commented in header.
SmartPtrRef *SmartPtrMakeRef( SmartPtr *pSmartPtr, OwnerPtr pReferenceOwner )
{
// TODO: Synchronization here!
SmartPtrRef *pRef = (SmartPtrRef *)malloc(sizeof(SmartPtrRef) );
LinkedListAddNode( &pSmartPtr->refList, &pRef->listNode );
pRef->pReferenceOwner = pReferenceOwner;
pRef->pObjectReferenced = pSmartPtr->pObjectRef;
pRef->pSmartPtr = pSmartPtr;
return pRef;
}
// Commented in header.
bool SmartPtrRemoveRef( SmartPtr *pSmartPtr, OwnerPtr pReferenceOwner )
{
// TODO: Synchronization here!
SmartPtrRef *pRef = SmartPtrFindRef( pSmartPtr, pReferenceOwner );
if (NULL != pRef) {
assert( LinkedListRemoveNode( &pSmartPtr->refList, &pRef->listNode ) );
pRef->pReferenceOwner = NULL;
pRef->pObjectReferenced = NULL;
free( pRef );
if (LinkedListIsEmpty( &pSmartPtr->refList ) ) {
pSmartPtr->ObjectDestructorFnPtr( pSmartPtr->pObjectRef );
}
}
return (NULL != pRef);
}
// Commented in header.
bool SmartPtrRefRemoveRef( SmartPtrRef *pRef )
{
return SmartPtrRemoveRef( pRef->pSmartPtr, pRef->pReferenceOwner );
}
// Commented in header.
void *SmartPtrRefGetObjectPtr( SmartPtrRef *pRef )
{
return pRef->pObjectReferenced;
}
// Commented in header.
SmartPtr *SmartPtrCreate( void *pObjectToReference, ObjectDestructorFunctionPtr Destructor )
{
SmartPtr *pThis = (SmartPtr *)malloc( sizeof( SmartPtr ) );
memset( pThis, 0, sizeof( SmartPtr ) );
LinkedListInit( &pThis->refList );
pThis->ObjectDestructorFnPtr = Destructor;
pThis->pObjectRef = pObjectToReference;
return pThis;
}
And a test program (main.cpp)
// SmartPtrs.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "SmartPointers.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
typedef struct tMyRefObj {
int refs;
SmartPtr *pPointerToMe;
bool deleted;
} MyRefObj;
static bool objDestructed = false;
static MyRefObj *MyObjectGetReference( MyRefObj *pThis, void *pObjectReferencing )
{
// TODO: Synchronization here...
pThis->refs++;
SmartPtrRef * const pRef = SmartPtrMakeRef( pThis->pPointerToMe, pObjectReferencing );
return (MyRefObj *)SmartPtrRefGetObjectPtr( pRef );
}
static void MyObjectRemoveReference( MyRefObj *pThis, void *pObjectReferencing )
{
// TODO: Synchronization here...
pThis->refs--;
assert( SmartPtrRemoveRef( pThis->pPointerToMe, pObjectReferencing ) );
}
static void MyObjectDestructorFunction(void *pObjectToDestruct)
{
MyRefObj *pThis = (MyRefObj *)pObjectToDestruct;
assert( pThis->refs == 0 );
free( pThis );
objDestructed = true;
}
static MyRefObj *MyObjectConstructor( void )
{
MyRefObj *pMyRefObj =new MyRefObj;
memset( pMyRefObj, 0, sizeof( MyRefObj ) );
pMyRefObj->pPointerToMe = SmartPtrCreate( pMyRefObj, MyObjectDestructorFunction );
return pMyRefObj;
}
#define ARRSIZE 125
int main(int argc, char* argv[])
{
int i;
// Array of references
MyRefObj *refArray[ARRSIZE];
// Create an object to take references of.
MyRefObj *pNewObj = MyObjectConstructor();
// Create a bunch of references.
for (i = 0; i < ARRSIZE; i++) {
refArray[i] = MyObjectGetReference( pNewObj, &refArray[i] );
}
assert( pNewObj->refs == ARRSIZE );
for (i = 0; i < ARRSIZE; i++) {
MyObjectRemoveReference( pNewObj, &refArray[i] );
refArray[i] = NULL;
}
assert(objDestructed);
return 0;
}