通过引用传递向量,然后调用清除

Pass Vector by Reference Then Call Clear

提问人:atomSmasher 提问时间:6/24/2017 更新时间:6/24/2017 访问量:238

问:

我很好奇,在通过引用后清除客户端 .cpp 中的向量时,我是否一直在处理未定义的行为?我从未遇到过无效数据的问题,但我可以看到这可能是潜伏的问题。通过引用一直传递到最终队列 - 同时,另一个线程将仅在触发后以自己的速率进行删除。data_receivedvectorqueue_event.notify_all()

如果这是一个问题,我相信解决方案可能会在阻止客户端>接收调用之后立即清除。思潮?

blocking_queue.h

template <typename T>
class BlockingQueue {
    ...
    std::queue<T> queue;
    ...
};

blocking_queue.cpp

template <class T>
void BlockingQueue<T>::enqueue(T const &item)
{
    std::unique_lock<std::mutex> lk (queue_lock);
    queue.push(item);
    lk.unlock();
    queue_event.notify_all(); 
}

template <class T>
T BlockingQueue<T>::dequeue()
{
    std::unique_lock<std::mutex> lk (queue_lock);
    if(queue_event.wait_for(lk, std::chrono::milliseconds(dequeue_timeout))  == std::cv_status::no_timeout)
    {
        T rval = queue.front();
        queue.pop();
        return rval;
    }
    else
    {
        throw std::runtime_error("dequeue timeout");
    }
}

客户端 .cpp

void Client::read_from_server()
{
    std::vector<uint8_t> data_received;

    while(run)
    {
        if (client->is_connected())
        {   
            uint8_t buf[MAX_SERVER_BUFFER_SIZE];
            int returned;

            memset(buf, 0, MAX_SERVER_BUFFER_SIZE);
            returned = client->receive(client->get_socket_descriptor(), buf, MAX_SERVER_BUFFER_SIZE);
            // should probably move data_received.clear() to here!!
            if (returned > 0)
            {
                for (int i = 0; i < returned; i++)
                {
                    data_received.push_back(buf[i]);
                }

                if (incoming_queue)
                {
                    incoming_queue->enqueue(data_received);
                }

                data_received.clear();
            }
            else
            {
                client->set_connected(false);
            }
        }    
    }
}
C++ 多线程 向量 引用传递 所有权

评论


答:

1赞 A.S.H 6/24/2017 #1

我没有看到任何潜在的 UB,因为调用时将保存传递的项目(向量)的副本。data_received.clear();std::queue<T> queue;incoming_queue->enqueue(data_received);

如果对队列的访问是同步的,这似乎是这种情况,那么代码应该是安全的。

评论

0赞 atomSmasher 6/24/2017
啊,这是在void std::queue push(const value_type& val)中做什么吗?const
2赞 A.S.H 6/24/2017
@atomSmasher这与性无关。明确指出,新元素被初始化为值的副本(或者如果值是临时的,或者编译器确定不再需要值的状态,则初始化为移动副本)。在你的情况下,它会被复制或移动,无论哪种情况,之后清除它都不会有任何问题。事实上,任何通过时都会复制或移动传递的 T。您只应该担心指针类型何时是。constpush_backTvector<uint8_t>container<T>TT
0赞 atomSmasher 6/24/2017
哇。你是对的。就是这样;明显。我想我需要新眼镜。