There are several points you need to consider here:
Your MTLBuffer object pointer does not point to the object's contents
MTLBuffer is a Metal framework object that manages a memory buffer on the GPU. The address you have is just the address of that object. For some buffers, Metal provides a way to access the contents of the buffer from the CPU by using the [MTLBuffer contents] method. contents returns a void * that you can directly use to read and write from your buffer, with the following caveats:
Your MTLBuffer's contents may not always be accessible from the CPU
It depends on which platform you're on. If you're solely on iOS/tvOS, just create your MTLBuffer with the MTLStorageModeShared storage mode, and you should be good to go -- Metal will ensure the data you see on the CPU is in sync with the GPU's view. On macOS it depends on which GPU you're using so there are some additional subtleties there. For now I'm assuming we're talking iOS/tvOS only.
There are several ways to combine Objective-C with C++ code
One option is to create Objective-C++ files (.mm files), and put all your Metal-specific code in a subclass within those .mm files. That would allow you to have the benefit of Objective-C's ARC (Automatic Reference Counting) and still create nice, generic C++ wrappers. In the header file for your Objective-C++ class, you would do something like this:
class MetalBuffer : GenericBuffer
{
private:
#ifdef __OBJC__
id <MTLBuffer> metalBuffer;
#else
void *internalMetalBuffer;
#endif
}
This would let your regular (non-Objective-C++) classes include the Objective-C++ header. I made the "special" managed pointer private to ensure no one tries to access it from outside the Objective-C++ class, as that would obviously be a bad idea.
If this approach isn't suitable, you could just do everything in C++, but then you'd have to manually track references to your Objective-C objects:
If you must store your objects in your C++ code as void pointers, you will need manual reference counting
Objective-C uses ARC to track object usage and to automatically release objects as appropriate. If you're trying to manage the whole thing in C++, you will need to manually manage references to your objects (such as your MTLBuffer and beyond). This is done by telling ARC that you wish to type-cast the managed, Objective-C id objects to regular C pointers.
After instantiating your MTLBuffer, you can use CFBridgingRetain() on your object, which now lets you store it as a void * (not to be confused with the void * you grabbed that points to the contents of your buffer!) in your C++ class. When you're done using the MTLBuffer, you can call CFRelease() on your void * to free it up. You do not need to worry about freeing the contents buffer -- the underlying memory will be freed automatically once the MTLBuffer object is released (such as when you call CFRelease()).
Note that you can use CFBridgingRelease() when you need to invoke Objective-C functions that use your MTLBuffer object (such as setFragmentBuffer, etc.) Think of CFBridgingRelease() as a converter that hands your object back to ARC, but note that it includes a manual release, which means that once Metal is done with your object, it will automatically be released.
If you want your object to live beyond the current Metal request, you should retain another pointer to it using CFBridgingRetain().
Again, this is a last resort -- I would not recommend taking this route.
Good luck!