c++ - 一对使用unique_ptr

标签 c++ c++11

我的代码:

template <typename T>//, T value_if_empty>
class AtomicQueue {
    std::mutex m;
    std::queue<T> q;
    T value_if_empty;

public:
    AtomicQueue(const T& emptyval) : value_if_empty(std::move(emptyval)) {};
    void push(const T& t)
    {
        m.lock();
        q.push(std::move(t));
        m.unlock();
    }
    T pop()
    {
        T a = std::move(value_if_empty);
        m.lock();
        if (!q.empty())
        {
            a = std::move(q.front());
            q.pop();
        }
        m.unlock();
        return a;
    }
};

AtomicQueue<int> A(0);
AtomicQueue<std::unique_ptr<Class1>> B(nullptr);
AtomicQueue < std::pair<int, std::unique_ptr<Class1>>> C({ 0,nullptr });

如果仅声明A和B,则此代码将编译,但同时声明C时,此代码将失败。错误是'std::pair<int,std::unique_ptr<Class1,std::default_delete<Class1>>>::pair(const std::pair<int,std::unique_ptr<Class1,std::default_delete<Class1>>> &)': attempting to reference a deleted function
问题似乎是std::pair<int, std::unique_ptr<Class1>>没有副本构造函数。但是std::unique_ptr<Class1>也是如此。那么为什么B的声明可以编译而C则不能呢?另外,在哪里使用复制构造函数?
抱歉,答案很简单。我是使用unique_ptr和移动构造函数的新手。

附带问题:是否有使用value_if_empty的更干净或更佳的方法?我不希望在使用unique_ptr时传递nullptr以外的任何东西。

编辑:B也不编译。 (如NathanOliver的评论中所述)。因此,现在的问题是如何消除此错误?

最佳答案

这是因为您不会在函数中移动任何东西。他们收到const T&,但是常量不能移动。在std::move上调用const将不会移动,并且绝对不会执行任何操作。

看,移动只是对右值的强制转换。实际移动发生在移动构造函数和移动分配中。这样的move构造函数的声明如下:

unique_ptr(unique_ptr&& other);

如您所见,它是一个非常量右值引用。由于无法调用move构造函数,因此它将尝试复制。这就是错误的根源。

那你怎么解决呢?

只需添加所需的重载并删除多余的 Action :
template <typename T>
class AtomicQueue {
    std::mutex m;
    std::queue<T> q;
    T value_if_empty;

public:
    // copy, it's an lvalue
    AtomicQueue(const T& emptyval) : value_if_empty(emptyval) {};

    // move, it's an rvalue
    AtomicQueue(T&& emptyval) : value_if_empty(std::move(emptyval)) {};

    void push(const T& t)
    {
        m.lock();
        q.push(t); // same here
        m.unlock();
    }

    void push(T&& t)
    {
        m.lock();
        q.push(std::move(t)); // same here
        m.unlock();
    }
    T pop()
    {
        T a = std::move(value_if_empty);
        m.lock();
        if (!q.empty())
        {
            a = std::move(q.front());
            q.pop();
        }
        m.unlock();
        return a;
    }
};

Live example

另请注意,您的类(class)中存在一个基本错误。看这行:
T a = std::move(value_if_empty);

如果pop被多次调用,则value_if_empty将从值中移出并返回。在返回未指定的值之前,您的pop函数只能被调用一次。

您需要复制value_if_empty,默认对其进行构造,或者将其替换为工厂函数,该工厂函数将返回新值(如果为空)。

我最喜欢的解决方案是默认构造它。

尽管如此,这里还是带有工厂功能的示例:
template <typename T>
class AtomicQueue {
    std::function<T()> make_empty_value;

public:
    T pop()
    {
        T a = make_empty_value();
        // ...
    }
};

然后在创建它时将其传递给您的类(class):
AtomicQueue<std::unique_ptr<Class1>> B([]{ return std::unique_ptr<Class1>{nullptr}; });

如果要避免std::function的开销,则可以用lambda类型的模板参数替换成员变量。

关于c++ - 一对使用unique_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60321167/

相关文章:

c++ - 不使用线性和二进制查找未排序数组的最大数量

VS 2013 中的 C++ 11 lambda 回调无法编译

c++ - 如何为 boolinq 实现 First 和 FirstOrDefault?

c++ - 从文本文件中读取直到空格的所有内容

C# 导入 C++ dll

c++ - try() 和 catch() 不工作;程序崩溃并且永远不会执行 catch() block

c++ - 确定类型是否派生自 CRTP 基类

c++ - C++ 中是否有任何与传输无关的 JSON-RPC 实现?

c++ - Centos6 gcc6 : default ABI not picked up when compiling simple c++11 test file

c++ - 具有 const 引用的可变参数模板