如何从仅提供复制构造函数的类中实例化“空”对象?

时间:2014-09-17 12:47:01

标签: c++ boost stl queue condition-variable

我实现了一个线程安全的模板化队列:

template<class T> class queue {

private:    
    boost::mutex mutex;
    boost::condition_variable emptyCondition;
    boost::condition_variable fullCondition;

    boost::scoped_ptr< std::queue<T> > std_queue;
     ...

public:
   ...

  T pop() {
        T r; // [*]
        {
            boost::mutex::scoped_lock popLock(mutex);
            while (queueIsEmpty())
                emptyCondition.wait(popLock);

            r = std_queue->front();
            std_queue->pop();
        }

        fullCondition.notify_one();    
        return r;
    }
     ...

我无法以我的方式实例化对象(标有[*]的地方),因为缺少T的构造函数,没有正式的参数。

那么:有没有办法,可能使用指向T的指针和复制构造函数(我知道它是为每个T实现的),以避免许多模板特化?

修改1

我也想过这个可能的解决方案。

T pop() {
    boost::mutex::scoped_lock popLock(mutex);
    while (queueIsEmpty())
        emptyCondition.wait(popLock);

    T r(std_queue->front());
    std_queue->pop();

    // update overall number of pop
    popNo++;

    popLock.unlock();
    fullCondition.notify_one();
    return r;
}

它会起作用吗?

2 个答案:

答案 0 :(得分:2)

此方案的一个选项是使用boost::optional

T pop() {
    boost::optional<T> r;
    {
        boost::mutex::scoped_lock popLock(mutex);
        while (queueIsEmpty())
            emptyCondition.wait(popLock);

        r = std_queue->front();
        std_queue->pop();
    }

    fullCondition.notify_one();    
    return *r;  // r is guaranteed to be engaged at this point
}

boost::optional在运行时会注意跟踪是否已构造其包含的T,因此是否需要销毁它。 (请注意,此处您实际上并不需要boost::mutex::scoped_lock; you can use boost :: lock_guard`的完整功能。)

另一种方法是注意scoped_lock可以释放:

T pop() {
    boost::mutex::scoped_lock popLock(mutex);
    while (queueIsEmpty())
        emptyCondition.wait(popLock);

    T r = std_queue->front();
    std_queue->pop();
    popLock.release();

    fullCondition.notify_one();    
    return r;
}

这里的缺点是popLock的范围不太清楚,代码更改可能导致不安全的代码或死锁。

答案 1 :(得分:0)

如果您手动解锁,可以摆脱括号,这样就无需预先创建T:

T pop() {
   boost::mutex::scoped_lock popLock(mutex);
   while (queueIsEmpty())
      emptyCondition.wait(popLock);

   T r = std_queue->front();
   std_queue->pop();
   popLock.unlock();

   fullCondition.notify_one();    
   return r;
}