Estoy trabajando en un programa de subprocesos múltiples donde se usa un "std :: deque myBuffer" como búfer FIFO, un subproceso productor agrega constantemente objetos personalizados al final de un deque usando push_back (), y un subproceso de consumo utiliza una función auxiliar para recuperar el objeto y manejar la sincronización y mutex.

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

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

    // other code

    return 0;
}

La función de productor:

void producer() {
    while (somecondition) {

        // code producing MyObject object

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

La función del consumidor:

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

Mi función de ayuda actual se ve así:

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

Sin embargo, rápidamente me di cuenta de que deque :: front () devuelve la referencia del primer elemento en el contenedor. Y "object" es MyObject &, por lo que, según tengo entendido, solo la referencia del primer elemento en la deque se pasa al objeto y, como resultado, cuando llamo a pop_front (), el elemento al que se hace referencia debería desaparecer y la variable de objeto es sosteniendo una referencia inválida. Sorprendentemente, cuando realmente ejecuté el código, todo funcionó en lugar de lo que esperaba. Entonces, ¿alguien podría ayudarme a entender cómo funciona este "deque :: front () devuelve la referencia"? Gracias.

0
xk103247 14 sep. 2018 a las 04:48

3 respuestas

La mejor respuesta

Funciona correctamente y este es el comportamiento esperado.

No asigna la referencia; no puede, las referencias de C ++ son inmutables. En realidad copia el valor. Así es como se supone que debe funcionar. La asignación semántica de foo = ... cuando foo es una referencia es aproximadamente: "copie el valor de la derecha en el lugar al que hace referencia foo".

Cuando hay una referencia en el lado derecho, el valor referenciado se copia.

En su caso, la línea object = myBuffer.front(); copia el valor frontal de deque a la variable object1 o object2 en consumer(), respectivamente a la llamada. La llamada posterior a .pop_front() destruye el valor en la deque, pero no afecta el valor ya copiado.

1
Frax 15 sep. 2018 a las 01:59

No puedo entender tu propósito, tal vez puedas probar deque :: at ()

0
Wjiyao 14 sep. 2018 a las 02:03

Pop_front () elimina el primer elemento de la cola. No elimina el objeto. Entonces, hacer referencia al objeto después de la llamada pop_front () debería funcionar.

Actualización

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

El programa anterior se puede usar para comprender el comportamiento. En el caso de los objetos, se llama al constructor de copias y se almacena una nueva copia en deque. Cuando se llama a pop_front (), la copia se elimina. Mientras que en caso de punteros, la dirección se copia. Por lo tanto, la dirección se elimina y no el objeto real al que hace referencia la dirección. Encontrará que no se llama a destructor en este caso.

0
Ajay Srivastava 15 sep. 2018 a las 01:39