【问题标题】:C++ -- determine if generic variable is a pointerC++——判断泛型变量是否为指针
【发布时间】:2013-12-30 03:34:47
【问题描述】:

我有一个类,我将其称为 myclass,它有一个类型为 T 的列表容器。我还有几个从列表中删除项目的方法。如果 T 是某种指针,我想检查它是否确实是一个指针,然后将其删除,以便将分配的资源释放回内存。这是一段sn-p代码:

template<typename T>
class myclass{
private:
    std::list<T> * container;
    // other vars
public:

    void erase(const T &item){
        if (!this->find(item))     // find is defined elsewhere
            return false;
        auto temp = container->begin();
        for (int i = 0; i < container->size(); ++i){
            // this is where i would like to check if *temp is a pointer,
            // so that I can assign it to a pointer var, remove it from the list,
            // then delete the pointer,
            //otherwise just simply remove it from the list.
        }
    }

};

编辑

auto temp = container->begin();

我想知道如何确定 *temp 是否是一个指针,以便我可以执行以下操作:

T * var = *temp;
container->remove(temp);   // remove or erase, i can't recall at the moment
delete var;

但我只想在 *temp 是指针的情况下这样做

【问题讨论】:

  • 我建议只让用户做 myclass<:unique_ptr>> 而不是指针 - 当用户想要释放原始指针时,你现在真的不需要,而智能指针将自行释放
  • std::is_pointer?会这样使用吗:if (std::is_pointer(pointer)) ?
  • std::is_pointer&lt;&gt; 是一个模板 type 条件。 IE。 std::is_pointer&lt;T&gt;::value,无论如何,我对此持大部分意见;这样做并不完全正确。
  • 关于您的编辑:*temp 是一个指针当且仅当 T 是一个指针类型。在*tempT 是指针类型的情况下,T* 将是指向指针类型的指针,而T* var = *temp 行将导致编译错误。你应该做delete *temp。但是请注意,即使*temp 是一个指针,也不能保证它指向已分配的内存,delete 可能会导致错误。

标签: c++ templates pointers containers


【解决方案1】:

1) Determine if Type is a pointer in a template function

2) 您如何知道该指针是否指向动态分配的内存?

【讨论】:

    【解决方案2】:

    对不起,但不是:std::list&lt;T&gt;::iterator(这是begin() 将返回的,因此将是temp 的类型)永远不能是指针。它必须是一种(至少)重载前后增量和减量以进行链表遍历的类型,因此++ 将执行类似pos = pos-&gt;next;-- 的操作类似于pos = pos-&gt;prev;

    如果您想弄清楚*temp(与T 的类型相同)是否是一个指针,那就完全不同了。你基本上有两条路线。作为一般规则,我更喜欢的一个是为您的类提供指针的专业化:

    template<typename T>
    class myclass{
    private:
        std::list<T> container;
        // other vars
    public:
    
        void erase(const T &item){
            if (!container->find(item))     // find is defined elsewhere
                return false;
            auto temp = container->begin();
            for (int i = 0; i < container->size(); ++i){
                container.erase(temp);
            }
        }
    
    };
    
    template<class T>
    class myclass <T *> {
    private:
        std::list<T> container;
        // other vars
    public:
    
        void erase(const T &item){
            if (!container->find(item))     // find is defined elsewhere
                return false;
            auto temp = container->begin();
            for (int i = 0; i < container->size(); ++i){
                delete *temp;
                container.erase(temp);
            }
        }
    };
    

    这样做的最大问题是您最终可能会在基本模板和指针的特化之间复制相当多的内容。有几种方法可以避免这种情况。一种是使用实现公共行为的基类,然后从中派生两个特化以提供特化行为。另一种方法是使用 enable_if 或 SFINAE 来启用不同版本的 erase 函数,具体取决于包含的类型是否可以取消引用。

    顺便说一句,您可能不应该有std::list&lt;T&gt; *container;——它可能应该只是std::list&lt;T&gt; container;(或者,在大多数情况下更好的是std::vector&lt;T&gt; container;

    【讨论】:

    • 您在提问者的代码中回答了准确的问题,但没有抓住重点。提问者想知道列表元素是否是指针,而不是 std::list 插入器是否是指针。他在询问 temp 而不是 *temp 时犯了一个错误。
    • 我确实意识到 begin() 返回一个迭代器。我决定使用一个列表,因为它的插入复杂度为 O(1)。我想我得到的是,如果有人将我的类用作容器,即 myclass,那么列表将包含字符串指针。现在有可能 *it 是一个指向字符串的指针吗?这样我就可以做到以下几点:string * var = *it; 然后delete var;
    【解决方案3】:

    我不认为这是一个明智的想法。您不知道用户是否提供了指向堆栈上分配的数据的指针,或者指向以其他方式管理的数据(例如使用智能指针)。

    但是要回答这个问题,请看

    std::is_pointer<T>::value  // in type_traits header
    

    http://en.cppreference.com/w/cpp/types/is_pointer

    这是一个 C++11 特性。

    【讨论】:

    • 这是解决 op 问题的基础,即使它不是一个好问题。取消投票
    【解决方案4】:

    容器不删除普通指针不是很烦人吗?那么在 C++ 中,原始指针实际上并不拥有该对象。可能有许多指针指向同一个对象。您需要一个唯一的指针 - stl 在 c++11 中提供了一个。当一个unique_ptr从列表中被移除时,它会破坏它指向的对象,所以不需要复杂的擦除。

    #include <list>
    #include <memory>
    #include <type_traits>
    
    using namespace std;
    
    template<typename t, bool b>
    struct Selector {
        typedef list<T> container;
    };
    
    template<typename t>
    struct Selector<t, true> {
        typedef list<unique_ptr<T> > container;
    };
    
    template<typename T>
    class myclass{
    private:
        Selector<T, is_pointer<T>::value>::container* container;
        // other vars
    public:
    
        void erase(const T &item){
            if (!this->find(item))     // find is defined elsewhere
                return false;
            auto temp = container->begin();
            for (int i = 0; i < container->size(); ++i){
                // removing the unique_ptr delete's pointer
            }
        }
    };
    

    【讨论】:

      猜你喜欢
      • 2011-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多