Carmine
Carmine

Reputation: 119

I have a problem creating a vector of blocking queues in C++

I'm trying to write a simple program that creates and uses a certain number (variable - it is a parameter passed by command line) of blocking queues. To easily access them, I thought about creating a vector of queues.

I'm using g++-8 to compile the program. The queue I have is provided by my professor, so I can't make any changes in its code.

Here is the code I've developed:

blocking_queue.hpp

    #ifndef SKYLINE_BLOCKING_QUEUE_HPP
    #define SKYLINE_BLOCKING_QUEUE_HPP

    #include <iostream>
    #include <mutex>
    #include <condition_variable>
    #include <deque>
    #include <vector>
    #include <chrono>
    #include <cstddef>
    #include <math.h>
    #include <string>
    #include <thread>


    using namespace std::literals::chrono_literals;

    //
    // needed a blocking queue
    // here is a sample queue.
    //

    template <typename T>
    class blocking_queue
    {
    private:
    std::mutex d_mutex;
    std::condition_variable d_condition;
    std::deque<T> d_queue;
    public:

    blocking_queue(){}

    void push(T const& value) {
        {
            std::unique_lock<std::mutex> lock(this->d_mutex);
            d_queue.push_front(value);
        }
        this->d_condition.notify_one();
    }

    T pop() {
        std::unique_lock<std::mutex> lock(this->d_mutex);
        this->d_condition.wait(lock, [=]{return !this->d_queue.empty(); });
        T rc(std::move(this->d_queue.back()));
        this->d_queue.pop_back();
        return rc;
    }

    bool is_empty() {
        std::unique_lock<std::mutex> lock(this->d_mutex);
        this->d_condition.wait(lock, [=]{return !this->d_queue.empty(); });
        printf("ADDED A INT\n");
        return false;
    }

    int size() {
        std::unique_lock<std::mutex> lock(this->d_mutex);
        return(d_queue.size());
    }

    };

    #endif // SKYLINE_BLOCKING_QUEUE_HPP

test.cpp

    int main(char argc, char* argv[]) {
        nw = atoi(argv[0]);
        vector<blocking_queue<int>> myVector;

        for(int i = 0; i < nw; i++) {
            myVector.emplace_back();             
        }

    }

When I try to compile the program, g++ gives me the following error:

error: use of deleted function ‘blocking_queue<int>::blocking_queue(blocking_queue<int>&&)’
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from ./test.cpp:10:
./blocking_queue.hpp:28:7: note: ‘blocking_queue<int>::blocking_queue(blocking_queue<int>&&)’ is implicitly deleted because the default definition would be ill-formed:
 class blocking_queue
       ^~~~~~~~~~~~~~
./blocking_queue.hpp:28:7: error: use of deleted function ‘std::mutex::mutex(const std::mutex&)’
In file included from /usr/include/c++/8/mutex:43,
                 from ./blocking_queue.hpp:9,
                 from ./test.cpp:10:
/usr/include/c++/8/bits/std_mutex.h:97:5: note: declared here
     mutex(const mutex&) = delete;
     ^~~~~
In file included from ./test.cpp:10:
./blocking_queue.hpp:28:7: error: use of deleted function ‘std::condition_variable::condition_variable(const std::condition_variable&)’
 class blocking_queue
       ^~~~~~~~~~~~~~

How can I solve the problem?

Upvotes: 1

Views: 187

Answers (2)

If you simply need to create a vector of nw elements you can do the following:

std::vector<blocking_queue<int>> myVector(nw);

The use of emplace_back could work, but when doing emplace_back the vector might need to resize and resize might trigger copies between old buffer and new buffer. See C++ vector emplace_back calls copy constructor . As far as I know if you have a noexcept move ctor, the vector will use it instead of copying but I do not know if this is a guaranteed optimization from the standard of something that an implementor could choose to do. Regardless, your class does not seem to be movable, because of some of its members, namely condition_variable and mutex. So using this particular object inside a vector could be problematic, depends on your use case.

If you need to be able to resize your container you can:

  1. Keep vector and use unique_ptr of the queue object to store elements inside the vector
  2. Use std::list that should not require to copy objects when resizing because it is a linked list.

In both cases you might lose performance

Upvotes: 3

ravenspoint
ravenspoint

Reputation: 20492

Try using emplace_back() instead of push_back().

push_back() uses the copy constructor, which seems to have been deleted.

Upvotes: 0

Related Questions