I am working on creating a function for a class and the parameter is declared as a void* however within the function I need to test if this void* is either a shared_ptr or unique_ptr is there a way to test for this type of situation?
This is what I am working with so far; my class is a template type and does not store any member variables. It has a default constructor and it can also be constructed by passing in either a shared_ptr<Type>
or an unique_ptr<Type>
and it is has multiple allocate()
functions where they do the same type of work.
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <memory>
#include <iostream>
template<class Type>
class Allocator {
public:
Allocator(){}
Allocator( Type type, void* pPtr );
Allocator( std::shared_ptr<Type>& pType );
Allocator( std::unique_ptr<Type>& pType );
// ~Allocator(); // Default Okay
void allocate( std::shared_ptr<Type>& pType );
void allocate( std::unique_ptr<Type>& pType );
void allocate( Type type, void* pPtr );
private:
Allocator( const Allocator& c ); // Not Implemented
Allocator& operator=( const Allocator& c ); // Not Implemented
}; // Allocator
#include "Allocator.inl"
#endif // ALLOCATOR_H
My *.cpp
file only has #include "Allocator.h"
since all of the implementations are within my *.inl
file.
My two constructors: Allocator( std::shared_ptr<Type>& pType );
& Allocator( std::unique_ptr<Type>& pType );
along with both matching allocate()
functions work fine. The constructor Allocator( Type type, void* pPtr );
and its matching function is where I am having trouble.
The constructor itself is straight forward since all it does is invoke the matching function passing to it the variables.
template<class Type>
Allocator<Type>::Allocator( Type type, void* pPtr ) {
allocate( type, eType, pPtr );
}
It is within the function implementation that I am struggling.
template<class Type>
void Allocator<Type>::allocate( Type type, void* pData ) {
if ( pData == reinterpret_cast<void*>( std::shared_ptr<Type ) ) {
std::shared_ptr<Type> pShared;
pShared.reset( new Type( type ) );
pData = reinterpret_cast<void*>( pShared );
} else if ( pData == reinterpret_cast<void*>( std::unique_ptr<Type ) ) {
std::unique_ptr<Type> pUnique;
pUnique.reset( new Type( type ) );
pData = reinterpret_cast<void*>( pUnique );
} else {
std::cout << "Error invalid pointer type passed in << std::endl
<< "must be either a std::shared_ptr<Type> << std::endl
<< "or a std::unique_ptr<Type> << std::endl;
}
}
Other than checking to see if the void*
passed in is either a std::shared_ptr<Type>
or a std::unique_ptr<Type>
the other questions I may have would be, is my use of reinterpret_cast<void*>
the correct way to convert a smart pointer to a void pointer and if not how can this be achieved?
A void*
pointer does not carry any type information. What you need to do is pass around an additional value along with the void*
to specify what the void*
points to, and then you can type-cast it accordingly.
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <memory>
#include <iostream>
template<class Type>
class Allocator {
public:
enum AllocateType { eSharedPtr, eUniquePtr };
Allocator() {}
Allocator( Type type, std::shared_ptr<Type>& pData );
Allocator( Type type, std::unique_ptr<Type>& pData );
// ~Allocator(); // Default Okay
void allocate( Type type, std::shared_ptr<Type>& pData );
void allocate( Type type, std::unique_ptr<Type>& pData );
private:
Allocator( const Allocator& c ); // Not Implemented
Allocator& operator=( const Allocator& c ); // Not Implemented
void allocate( Type type, AllocateType eDataType, void* pData );
}; // Allocator
#include "Allocator.inl"
#endif // ALLOCATOR_H
template<class Type>
Allocator<Type>::Allocator( Type type, std::shared_ptr<Type>& pData ) {
allocate( type, pData );
}
template<class Type>
Allocator<Type>::Allocator( Type type, std::unique_ptr<Type>& pData ) {
allocate( type, pData );
}
template<class Type>
void Allocator<Type>::allocate( Type type, std::shared_ptr<Type>& pData ) {
allocate( type, eSharedPtr, &pData );
}
template<class Type>
void Allocator<Type>::allocate( Type type, std::unique_ptr<Type>& pData ) {
allocate( type, eUniquePtr, &pData );
}
template<class Type>
void Allocator<Type>::allocate( Type type, AllocateType eDataType, void* pData ) {
switch (eDataType) {
case eSharedPtr: {
static_cast<std::shared<Type>*>(pData)->reset( new Type( type ) );
break;
}
case eUniquePtr: {
static_cast<std::unique_ptr<Type>*>(pData)->reset( new Type( type ) );
break;
}
}
}
In which case, I wouldn't even bother trying to funnel everything through a single function to begin with:
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <memory>
#include <iostream>
template<class Type>
class Allocator {
public:
Allocator() {}
Allocator( Type type, std::shared_ptr<Type>& pData );
Allocator( Type type, std::unique_ptr<Type>& pData );
// ~Allocator(); // Default Okay
void allocate( Type type, std::shared_ptr<Type>& pData );
void allocate( Type type, std::unique_ptr<Type>& pData );
private:
Allocator( const Allocator& c ); // Not Implemented
Allocator& operator=( const Allocator& c ); // Not Implemented
}; // Allocator
#include "Allocator.inl"
#endif // ALLOCATOR_H
template<class Type>
Allocator<Type>::Allocator( Type type, std::shared_ptr<Type>& pData ) {
allocate( type, pData );
}
template<class Type>
Allocator<Type>::Allocator( Type type, std::unique_ptr<Type>& pData ) {
allocate( type, pData );
}
template<class Type>
void Allocator<Type>::allocate( Type type, std::shared_ptr<Type>& pData ) {
pData.reset( new Type( type ) ) ;
}
template<class Type>
void Allocator<Type>::allocate( Type type, std::unique_ptr<Type>& pData ) {
pData.reset( new Type( type ) );
}