测试传入函数的 void* 是 shared_ptr 还是 unique_ptr

Testing if a void* passed into a function is either a shared_ptr or a unique_ptr

我正在为 class 创建一个函数,参数被声明为 void* 但是在函数中我需要测试这个 void* 是 shared_ptr 还是 unique_ptr 有没有办法测试这种情况?

这是我目前正在使用的;我的 class 是模板类型,不存储任何成员变量。它有一个默认的构造函数,它也可以通过传入 shared_ptr<Type>unique_ptr<Type> 来构造,它有多个 allocate() 函数,它们做相同类型的工作。

#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

我的 *.cpp 文件只有 #include "Allocator.h",因为所有实现都在我的 *.inl 文件中。

我的两个构造函数:Allocator( std::shared_ptr<Type>& pType ); & Allocator( std::unique_ptr<Type>& pType ); 以及两个匹配的 allocate() 函数工作正常。构造函数 Allocator( Type type, void* pPtr ); 及其匹配函数是我遇到问题的地方。

构造函数本身很简单,因为它所做的只是调用传递给它的变量的匹配函数。

template<class Type>
Allocator<Type>::Allocator( Type type, void* pPtr ) {
    allocate( type, eType, pPtr );
}

我正在苦苦挣扎的是功能实现。

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;
    }            
}

除了检查传入的 void*std::shared_ptr<Type> 还是 std::unique_ptr<Type> 之外,我可能还有其他问题,我使用 reinterpret_cast<void*> 将智能指针转换为 void 指针的正确方法,如果不是,如何实现?

您无法检查 void* 是什么类型。这是一个void*。而已。它不像 boost::any 那样巧妙地隐藏了一些其他类型的信息。 只是 void*。您无法检查它来自什么类型。您无法测试它是否来自特定类型。你的信息为零。压缩。纳达。 Zilch。空白。

一个void*指针不携带任何类型信息。您需要做的是传递一个附加值以及 void* 以指定 void* 指向的内容,然后您可以相应地对其进行类型转换。

#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;
        }
    }
}

在这种情况下,我什至不会费心尝试通过单个函数汇集所有内容:

#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 ) );
}

经过一番考虑,我知道这个 class 不会在内部存储任何成员变量,只包含执行特定任务的函数,我采用了不同的方法。我非常感谢每个人的反馈和回答,因为他们确实对我最初提出的基本问题给出了很好的有效答案。这就是我从你的建议中得到的结果。我删除了这个 class 本身是模板的规定,我将默认构造函数设为私有。我确保每个函数都是一个函数模板并将它们设为静态。这是我的新 class:

Allocator.h

#ifndef ALLOCATOR_H
#define ALLOCATOR_H

#include <memory>

class Allocator {
public:
    template<class Type>
    inline static void allocate( std::shared_ptr<Type>& pShared, const Type& type = Type() );

    template<class Type>
    inline static void allocate( std::unique_ptr<Type>& pUnique, const Type& type = Type() );

private:
    Allocator();
    Allocator( const Allocator& c );
    Allocator& operator=( const Allocator& c );

}; // Allocator

#include "Allocator.inl"

#endif // Allocator

Allocator.cpp

#include "Allocator.h"

Allocator.inl

template<class Type>
inline void Allocator::allocate( std::shared_ptr<Type>& pShared, const Type& type ) {
    pShared.reset( new Type( type ) );  
}

template<class Type>
inline void Allocator::allocate( std::unique_ptr<Type>& pUnique, const Type& type ) {
    pUnique.reset( new Type( type ) );
}

这使得 class 的使用变得简单。

main.cpp

#include <iostream>
#include <conio.h>

#include "Allocator.h"

class A {
private:
    int m_a;
public:
    explicit A( int a = 0 ) : m_a( a ) {}
    A( const A& a ) { this->m_a = a.m_a; }

    int  getA() const { return m_a; }
    void setA( int a ) { m_a = a; }
}; // A

int main() {

    // Creating Smart A Pointer Just From A Class Type
    std::shared_ptr<A> pShared;
    std::unique_ptr<A> pUnique;

    Allocator::allocate( pShared );
    Allocator::allocate( pUnique );

    std::cout << "Shared: " << pSharedA->getA() << std::endl;
    std::cout << "Unique: " << pUniqueA->getA() << std::endl;

    pSharedA->setA( 4 );
    pUniqueA->setA( 5 );

    std::cout << "Shared: " << pSharedA->getA() << std::endl;
    std::cout << "Unique: " << pUniqueA->getA() << std::endl;

    // Create A Smart Pointer From An Object Of Type In This Case A
    // This next sections does rely on the fact that Type in this case A, should have a copy constructor defined.

    A a1( 3 );
    std::shared_ptr<A> sharedA;
    std::unique_ptr<A> uniqueA;
    Allocator::allocate( sharedA, a1 );
    Allocator::allocate( uniqueA, a1 );

    std::cout << "Shared: " << sharedA->getA() << std::endl;
    std::cout << "Unique: " << uniqueA->getA() << std::endl;

    sharedA->setA( 6 );
    uniqueA->setA( 7 );

    std::cout << "Shared: " << sharedA->getA() << std::endl;
    std::cout << "Unique: " << uniqueA->getA() << std::endl;

    pSharedA.reset();
    pUniqueA.release();
    pUniqueA.reset();

    sharedA.reset();
    uniqueA.release();
    uniqueA.reset();

    std::cout << std::endl << "Press Any Key To Quit" << std::endl;
    _getch();

    return 0;

} // main

这也消除了进行任何类型转换、比较等操作的需要,从而提高了工作效率。我什至可以通过将所有这些函数声明为内联来更进一步。

编辑

我听取了 Remy Lebeau 的建议,通过添加 Type type 作为默认参数删除了两个重载函数,并将其更改为通过 const 引用传递。我还内联了函数。