Skip to content

Instantly share code, notes, and snippets.

@steipete
Last active May 16, 2020 02:50
Show Gist options
  • Save steipete/0f65c234ee843ed514ff to your computer and use it in GitHub Desktop.
Save steipete/0f65c234ee843ed514ff to your computer and use it in GitHub Desktop.
A C++ smart pointer for CoreFoundation objects
// hpp:
/// A smart pointer that can manage the lifecycle of Core Foundation objects.
template<typename T>
class CFPointer {
public:
CFPointer() : storage(nullptr) { }
CFPointer(T pointer) : storage(toStorageType(pointer)) {
if (storage) {
CFRetain(storage);
}
}
CFPointer(const CFPointer & other) : storage(other.storage) {
if (CFTypeRef ptr = storage) {
CFRetain(ptr);
}
}
CFPointer(CFPointer && other) : storage(std::exchange(other.storage, nullptr)) { }
~CFPointer() {
if (CFTypeRef pointer = storage) {
CFRelease(pointer);
}
}
static inline CFPointer<T> adopt(T CF_RELEASES_ARGUMENT ptr);
T get() const;
CFPointer &operator=(CFPointer);
private:
CFTypeRef storage;
enum AdoptTag { Adopt };
CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) { }
inline CFTypeRef toStorageType(CFTypeRef ptr) const {
return (CFTypeRef)ptr;
}
inline T fromStorageType(CFTypeRef pointer) const {
return (T)pointer;
}
void swap(CFPointer &);
};
template<typename T>
CFPointer<T> CFPointer<T>::adopt(T CF_RELEASES_ARGUMENT ptr) {
return CFPointer<T>(ptr, CFPointer<T>::Adopt);
}
template<typename T>
T CFPointer<T>::get() const {
return fromStorageType(storage);
}
template<typename T>
inline CFPointer<T>& CFPointer<T>::operator=(CFPointer other) {
swap(other);
return *this;
}
template<typename T>
inline void CFPointer<T>::swap(CFPointer &other) {
std::swap(storage, other.storage);
}
// cpp:
/// A smart pointer that can manage the lifecycle of Core Foundation objects.
template<typename T>
class CFPointer {
public:
CFPointer() : storage(nullptr) { }
CFPointer(T pointer) : storage(toStorageType(pointer)) {
if (storage) {
CFRetain(storage);
}
}
CFPointer(const CFPointer & other) : storage(other.storage) {
if (CFTypeRef ptr = storage) {
CFRetain(ptr);
}
}
CFPointer(CFPointer && other) : storage(std::exchange(other.storage, nullptr)) { }
~CFPointer() {
if (CFTypeRef pointer = storage) {
CFRelease(pointer);
}
}
static inline CFPointer<T> adopt(T CF_RELEASES_ARGUMENT ptr);
T get() const;
CFPointer &operator=(CFPointer);
private:
CFTypeRef storage;
enum AdoptTag { Adopt };
CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) { }
inline CFTypeRef toStorageType(CFTypeRef ptr) const {
return (CFTypeRef)ptr;
}
inline T fromStorageType(CFTypeRef pointer) const {
return (T)pointer;
}
void swap(CFPointer &);
};
template<typename T>
CFPointer<T> CFPointer<T>::adopt(T CF_RELEASES_ARGUMENT ptr) {
return CFPointer<T>(ptr, CFPointer<T>::Adopt);
}
template<typename T>
T CFPointer<T>::get() const {
return fromStorageType(storage);
}
template<typename T>
inline CFPointer<T>& CFPointer<T>::operator=(CFPointer other) {
swap(other);
return *this;
}
template<typename T>
inline void CFPointer<T>::swap(CFPointer &other) {
std::swap(storage, other.storage);
}
@StatusReport
Copy link

@steipete, I just watched your AltConf lecture - thanks for the tips! Is there any specific reason you've re-implemented unique_ptr instead of just implementing a custom deleter (or a specialization of std::default_delete) that calls CFRelease?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment