C++:如何正确地将 deque::front() 返回的变量传递出函数?

C++: how to properly pass a variable returned by deque::front() out of a function?

我正在开发一个多线程程序,其中 "std::deque< MyObject > myBuffer" 用作 FIFO 缓冲区,生产者线程使用 push_back() 不断将自定义对象添加到双端队列的末尾,并且消费者线程使用辅助函数来检索对象并处理同步和互斥锁。

std::deque< MyObject > myBuffer;
std::mutex mtx;

int main() {
    std::thread producerThread(producer());
    std::thread consumerThread(consumer());

    // other code

    return 0;
}

生产者函数:

void producer() {
    while (somecondition) {

        // code producing MyObject object

        std::lock_guard<std::mutex> lck(mtx);
        myBuffer.push_back(object);
    }
}

消费者函数:

void consumer() {
    while(somecondition) {
        MyObject object1, object2;
        if (retrieve(object1)) {
            // process object1
        }
        if (retrieve(object2)) {
            // process object2
        }
    }
}

我当前的辅助函数如下所示:

bool retrieve(MyObject & object) {
    // other code ...
    std::lock_guard<std::mutex> lck(mtx);
    if (!myBuffer.empty()) {
        object = myBuffer.front();
        myBuffer.pop_front();
        return true;
    } else {
        return false;
    }
}

不过,我很快意识到deque::front() returns容器中第一个元素的引用。 "object" 是 MyObject&,所以根据我的理解,只有双端队列中第一个元素的引用被传递给对象,因此当我调用 pop_front() 时,引用的元素应该是消失了,对象变量持有无效引用。令人惊讶的是,当我实际 运行 代码时,一切都与我预期的相反。那么谁能帮我理解 "deque::front() returns the reference" 是如何工作的?谢谢。

我不明白你的目的,也许你可以试试deque::at()

pop_front() 从队列中移除第一个元素。它不会删除对象。因此,在 pop_front() 调用之后引用对象应该有效。

更新-

#include <iostream>
#include <queue>
#include <algorithm>

class newClass {
public:
    newClass () {
    }

    ~newClass () {
        std::cout << " Destructor is called. " << "\n";
    }

    newClass(const newClass &obj) {
        std::cout << "Copy is called." << "\n";
    }

    void print(void) {
        std::cout << "Hi there !" << "\n";
    }
};

void queueWithPointer(void) {
    std::deque<newClass *> deque;
    deque.push_back(new newClass());
    deque.push_front(new newClass());
    newClass *b = deque.front();
    std::cout << "pop_front starts" << "\n";
    deque.pop_front();
    std::cout << "pop_front ends" << "\n";
    b->print();
}

void queueWithObjects(void) {
    std::deque<newClass> deque;
    deque.push_back(newClass());
    deque.push_front(newClass());
    newClass ba = deque.front();
    std::cout << "pop_front starts" << "\n";
    deque.pop_front();
    std::cout << "pop_front ends" << "\n";
    ba.print();
}

int main()
{
    queueWithPointer();
//  queueWithObjects();

    return 0;
}

以上程序可用于理解行为。对于对象,调用复制构造函数并将新副本存储在双端队列中。当 pop_front() 被调用时,副本被删除。而在指针的情况下,地址被复制。因此,删除的是地址,而不是地址引用的实际对象。你会发现在这种情况下并没有调用析构函数。

它工作正常,这是预期的行为。

您不分配引用 - 您不能,C++ 引用是不可变的。您实际上复制了该值。这就是它应该如何工作的。当 foo 是引用时 foo = ... 赋值的语义大致是: "copy the right-hand value to the place referenced by foo".

当右侧有引用时,复制引用的值

在你的例子中,object = myBuffer.front(); 行将 deque 的前端值复制到 consumer() 中的变量 object1object2,分别到调用。稍后调用 .pop_front() 会破坏双端队列中的值,但不会影响已复制的值。