【问题标题】:Testing if a void* passed into a function is either a shared_ptr or a unique_ptr测试传递给函数的 void* 是 shared_ptr 还是 unique_ptr
【发布时间】:2016-01-05 08:25:09
【问题描述】:

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

这是我目前正在使用的;我的类是模板类型,不存储任何成员变量。它有一个默认构造函数,也可以通过传入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&lt;Type&gt;&amp; pType );Allocator( std::unique_ptr&lt;Type&gt;&amp; 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&lt;Type&gt;还是std::unique_ptr&lt;Type&gt;之外,我可能还有其他问题,我使用reinterpret_cast&lt;void*&gt;是转换智能指针的正确方法吗到一个空指针,如果不是,如何实现?

【问题讨论】:

  • 奇怪的东西。有什么需要?
  • 没有基本的需要,只是一个自我想要的练习来加强我的模板技能。我认为这将是一个不错的实用程序类型类,您可以在其中使用所需类型对其进行实例化,然后调用其成员函数来创建该类型的 shared_ptr 或 unique_ptr,或者使用其构造函数来做同样的事情。
  • 你根本做不到,void 指针不携带任何类型信息,除非你可以使用合理的reinterpret_cast 来暗示它,在那里你完全知道如何解释内存void* 指针指向的布局。
  • 您的void* 是否指向共享/唯一指针?或者它是否指向共享/唯一 ptr 指向的内容?或者您是否真的试图将共享/唯一 ptr 的字节重新解释为void*?如果第三种可能性(正如您的其他代码所暗示的那样),那么我认为您注定要失败。在其他问题中,不能保证 void 指针的大小与共享/唯一指针的大小相同(我相信 shared_ptr 可能永远不会是相同的大小)。
  • 当函数被调用或调用时,该方法不知道用户是要传入 shared_ptr 还是 unique_ptr。我在它的声明中使用了 void*,但是当使用该函数时,需要传入一个或另一个。

标签: c++ smart-pointers void-pointers reinterpret-cast


【解决方案1】:

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

【讨论】:

  • 奇怪的机器/编译器特定的黑客(金丝雀等)可能适用。虽然没有这样做的标准方法,但完全同意。
  • 我正在考虑这个问题,所以如果无法检查传递给函数的指针是否是一种类型,我怎么知道要调用哪个方法?如果一个人通过 shared_ptr 而不是 unique_ptr 这就是我卡住的地方。我正在考虑使用要指定的枚举类型,但是如果使用 SHARED_PTR 枚举但传入了 unique_ptr,那将是一个问题,反之亦然。
  • @FrancisCugler 您实际上应该传递智能指针 - 而不是 void*。如果您确实需要,请不要将类型信息放在地板上!
  • 在大家的反馈下,我能够改进这门课,我提供了它作为答案。
【解决方案2】:

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

【讨论】:

  • 这就是我的目标,感谢您的澄清。但是我确实注意到您使用的是 static_cast 而不是 reinterpret_cast。但是,由于此类不存储任何内部值,并且只有成员函数。我走了一条不同的路。
  • reinterpret_cast 用于在整数和指针之间或在不相关的指针类型之间进行转换时使用。不过,这并不真正包括void*。您可以将static_castvoid* 转换为任何其他指针类型(任何指针类型都可以直接分配给void*,而无需使用强制转换)。
  • Labeau 感谢您提供的信息;我经常使用 static_cast 和 dynamic_cast,但我没有使用 reinterpret_cast 那么多。感谢您轻松阐明主要区别。
  • 在大家的反馈下,我能够改进这门课,我提供了它作为答案。
【解决方案3】:

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

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

这使得使用这个类变得简单。

ma​​in.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 引用传递。我还内联了这些函数。

【讨论】:

  • 您实际上并不需要额外的 2 个具有 type 参数的 allocate() 重载。当调用者未指定时,您可以有 2 个具有默认值的 type 参数的重载,例如:static void allocate( std::shared_ptr&lt;Type&gt;&amp; pShared, Type type = Type() ); ... Allocator::allocate( pShared ); ... Allocator::allocate( shared, a1 ); 您还可以考虑将 Type type 更改为 const Type &amp;type 以避免不必要的复制。
  • @Remy Lebeau 非常正确;我没有考虑那个。我想我会编辑此答案以反映您的回复。
猜你喜欢
  • 2014-11-12
  • 2011-07-31
  • 2012-03-30
  • 2013-01-30
  • 2018-03-12
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
相关资源
最近更新 更多