0

I am trying to create a structure and insert that a map as following:

    struct Queue_ctx {
      std::mutex qu_mutex;
      std::condition_variable qu_cv;
      std::queue<std::vector<std::byte>> qu;
    };

    std::map<std::string, Queue_ctx> incoming_q_map;
    Queue_ctx qctx;
    std::vector<std::byte> vect(100);
    qctx.qu.push(vect);
    incoming_q_map.emplace("actor", qctx);

But I get the following error :

error C2660: 'std::pair<const std::string,main::Queue_ctx>::pair': function does not take 2 arguments
 
message : see declaration of 'std::pair<const std::string,main::Queue_ctx>::pair'

message : see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const char(&)[6],main::Queue_ctx&>(_Alloc &,_Objty *const ,const char (&)[6],main::Queue_ctx &)' being compiled
        with
        [
            _Alloc=std::allocator<std::_Tree_node<std::pair<const std::string,main::Queue_ctx>,std::_Default_allocator_traits<std::allocator<std::pair<const std::string,main::Queue_ctx>>>::void_pointer>>,
            _Ty=std::pair<const std::string,main::Queue_ctx>,
            _Objty=std::pair<const std::string,main::Queue_ctx>
        ]

AFAIU, emplace constructs the element inplace. if that is true then why compiler is trying to create pair to emplace? I see that the syntax of pair synthesized by the compiler is odd that's why it complains. But why does that happen and what can I do to fix this problem ?

I tried to pass make_pair() explicitly but that did not help.

If I comment the qu_mutex and qu_cv then I am able to do emplace. What does error has to do with these two members? Isn't the case that default consutructor initializing the members of struct ? I know copy/assignment/move constructors are deleted by the compiler.

Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39
irsis
  • 952
  • 1
  • 13
  • 33
  • 7
    A `std::mutex` isn't copyable. – ChrisMM Nov 23 '22 at 16:33
  • @ChrisMM Hmm so does `std::condition_variable` and it perfectly makes sense but then error messages is so misleading. It probably answers my question. Thanks. But I would still be interested to know why does compiler emits such message. – irsis Nov 23 '22 at 16:36
  • 1
    Something related: [Safe and effective way to put a mutex on a container entry](https://stackoverflow.com/questions/27276555/safe-and-effective-way-to-put-a-mutex-on-a-container-entry) – Ranoiaetep Nov 23 '22 at 16:37
  • 1
    Somewhere deeper in logs it should say that mutex is not copy-able. – Marek R Nov 23 '22 at 16:37
  • @MarekR Unfortunately, I could did not find that in the logs emitted by the visual studio. – irsis Nov 23 '22 at 16:41
  • Try using `try_emplace` instead of `emplace` should give you a much better error message. – Ranoiaetep Nov 23 '22 at 16:43
  • @Ranoiaetep @MarekR Indeed it does with `try_emplace` , `Error C2280 'attempting to reference a deleted function` – irsis Nov 23 '22 at 16:49
  • C++ error messages can be quite opaque. They are getting better — which is little consolation — but the future will be better. – Eljay Nov 23 '22 at 18:31

1 Answers1

1

Anyway to fix this problem you need customize copy constructor and assignment operator. Also mutex suggest some synchronization of qu in all scenerios, so all fields should be private (so struct should be changed to class).

class Queue_ctx {
    mutable std::mutex qu_mutex;
    std::condition_variable qu_cv;
    std::queue<std::vector<std::byte>> qu;

public:
    Queue_ctx() = default;
    Queue_ctx(const Queue_ctx& other)
        : Queue_ctx(other, std::scoped_lock{ other.qu_mutex })
    {
    }

    Queue_ctx(const Queue_ctx& other, const std::scoped_lock<std::mutex>&)
        : qu { other.qu }
    {
    }

    Queue_ctx(Queue_ctx&& other)
    : Queue_ctx(std::move(other), std::scoped_lock{ other.qu_mutex })
    {
    }

    Queue_ctx(Queue_ctx&& other, const std::scoped_lock<std::mutex>&)
        : qu { std::move(other.qu) }
    {
    }

    Queue_ctx& operator=(const Queue_ctx& other)
    {
        std::scoped_lock lock{ qu_mutex, other.qu_mutex };
        qu = other.qu;
        return *this;
    }

    Queue_ctx& operator=(Queue_ctx&& other)
    {
        std::scoped_lock lock{ qu_mutex, other.qu_mutex };
        qu = std::move(other.qu);
        return *this;
    }

    void push(const std::vector<std::byte>& v)
    {
        std::unique_lock lock{ qu_mutex };
        qu.push(v);
    }

    void push(std::vector<std::byte>&& v)
    {
        std::unique_lock lock{ qu_mutex };
        qu.push(std::move(v));
    }
};

https://godbolt.org/z/xn6orTedz

It compiles, but more testing is required. Note some functionality is missing to utilize qu_cv.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Thank you, I accept this answer. But the way I solve the problem is replacing the `std::map` with `std::array`. The key was not really a `string` but an `enum` so it it possible to use std::array for my use case. – irsis Nov 23 '22 at 19:09