代码之家  ›  专栏  ›  技术社区  ›  Yura

如何将UpQuyPPTR推向DeQuy?

  •  0
  • Yura  · 技术社区  · 6 年前

    在我的项目中,我需要一个容器来保存指向数据单元实例的智能指针。我写这门课(简单的例子):

    template <typename T>
    class Queue
    {
    public:
    
        void push(const T & param) 
        {
            m_deque.push_front(param);
        }
    
    private:
        std::deque<T> m_deque;
    };
    

    比我想推那个:

    int main()
    {
    
        Queue< std::unique_ptr<DataBox> > queue;
    
        std::unique_ptr<DataBox> d1(new DataBox(11));
    
        queue.push(d1);
    
        return 0;
    }
    

    VS2017编译器说我不能这样做:

    Error C2280 std::unique_ptr<DataBox,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function

    据我所知,错误的原因是试图复制unique_ptr。但如果我把签名改成:

    void push(T && param) {...}

    以及函数调用

    queue.push( std::move(d1) );

    我又犯了这个错误。所以问题是-我应该如何实现 push() 会移动的 unique_ptr 排队吗?

    3 回复  |  直到 6 年前
        1
  •  1
  •   Killzone Kid    6 年前

    如果你想让它具有普遍性,那么 push 可以采用l或r值,您可以尝试以下方法:

    #include <iostream>
    #include <memory>
    #include <deque>
    #include <utility>
    
    class DataBox 
    {
    public:
        DataBox(int i) {}
    };
    
    template <typename T>
    class Queue
    {
    public:
        template <typename U>
        void push(U &&param)
        {
            m_deque.push_front(std::forward<T>(param));
        }
    
    private:
        std::deque<T> m_deque;
    };      
    
    int main()
    {
        Queue<std::unique_ptr<DataBox>> queue;
        std::unique_ptr<DataBox> d1 = std::make_unique<DataBox>(11);
        std::unique_ptr<DataBox> d2 = std::make_unique<DataBox>(22);
        queue.push(d1);
        queue.push(std::move(d2));
    
        return 0;
    }
    

    https://ideone.com/ixzEmN

        2
  •  3
  •   Jarod42    6 年前

    您应该修改类以处理仅移动类型:

    template <typename T>
    class Queue
    {
    public:
    
        void push(const T & param) 
        {
            m_deque.push_front(param);
        }
    
        void push(T&& param) 
        {
            m_deque.push_front(std::move(param));
        }
    
    
    private:
        std::deque<T> m_deque;
    };
    

    使用情况:

    int main()
    {
        Queue< std::unique_ptr<DataBox> > queue;
    
        std::unique_ptr<DataBox> d1(new DataBox(11));
    
        queue.push(std::move(d1));
    }
    
        3
  •  0
  •   Andrei Matveiakin    6 年前

    你有以下选择。

    选择1:简洁且通常快速

    template <typename T>
    class Queue {
    public:
        void push(T param) {
            m_deque.push_front(std::move(param));
        }
    
    private:
        std::deque<T> m_deque;
    };
    

    我建议在大多数实际案例中使用这个,因为它很简单。但是,如果 T 无法有效移动,它将复制两份而不是一份。

    选项2:始终快速

    template <typename T>
    class Queue {
    public:
        void push(const T& param) {
            m_deque.push_front(param);
        }
        void push(T&& param) {
            m_deque.push_front(std::move(param));
        }
    
    private:
        std::deque<T> m_deque;
    };
    

    这是最理想的解决方案,但可能有点过头了。如果 T型 是可有效移动的(您应该努力使所有类型的文件都能有效移动),那么它的复制量与选项1完全相同:

    Queue<std::vector<int>> q;
    std::vector<int> v;
    q.push(v);             // one copy, both with option 1 and option 2
    q.push(std::move(v));  // no copies, both with option 1 and option 2
    

    然而:

    Queue<NotEfficientlyMovableType> q;
    NotEfficientlyMovableType x;
    q.push(x);             // one copy with option 2, two copies with option 1
    q.push(std::move(x));  // same (so it doesn't really make sense)
    

    选项3:简洁,总是很快,但是有一些注意事项

    template <typename T>
    class Queue {
    public:
        template <typename U>
        void push(U&& param)
        {
            m_deque.push_front(std::forward<T>(param));
        }
    
    private:
        std::deque<T> m_deque;
    };
    

    对于选项3,您只需编写一个函数,它总是执行最少的副本数(如选项2)。但是,它需要模板参数推导,这可能会破坏有效代码。例如,这适用于选项1和2,但不适用于选项3:

    Queue<std::pair<int, int>> q;
    q.push({1, 2});