C ++: как правильно передать переменную, возвращаемую deque :: front (), из функции? - PullRequest
0 голосов
/ 14 сентября 2018

Я работаю над многопоточной программой, в которой "std :: deque myBuffer" используется в качестве буфера FIFO, поток производителя постоянно добавляет пользовательские объекты в конец deque с помощью 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 () возвращает ссылку на первый элемент в контейнере.И «объект» - это MyObject &, поэтому, насколько я понимаю, только ссылка на первый элемент в deque передается объекту, и в результате, когда я вызываю pop_front (), указанный элемент должен быть удален, а переменная объектадержит недействительную ссылку.Удивительно, но когда я фактически запустил код, все работало в противоположность тому, что я ожидал.Так может ли кто-нибудь помочь мне понять, как работает "deque :: front () возвращает ссылку"?Спасибо.

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

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;
}

Приведенная выше программа может использоваться для понимания поведения.В случае объектов вызывается конструктор копирования, а новая копия сохраняется в deque.Когда вызывается pop_front (), копия удаляется.Пока в случае указателей, адрес копируется.Таким образом, адрес удаляется, а не фактический объект, на который ссылается адрес.Вы обнаружите, что деструктор в этом случае не вызывается.

0 голосов
/ 15 сентября 2018

Работает нормально, и это ожидаемое поведение.

Вы не назначаете ссылку - вы не можете, ссылки C ++ неизменны. Вы фактически копируете значение. Вот как это должно работать. Семантика присваивания foo = ..., когда foo является ссылкой, примерно равна msgstr "скопировать правое значение в место, на которое ссылается foo".

Если справа имеется ссылка, ссылочное значение копируется.

В вашем случае строка object = myBuffer.front(); копирует переднее значение deque в переменную object1 или object2 в consumer(), соответственно, на вызов. Позже вызов .pop_front() уничтожает значение в очереди, но не влияет на уже скопированное значение.

0 голосов
/ 14 сентября 2018

Я не могу понять вашу цель, Может быть, вы можете попробовать deque :: at ()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...