0

I was trying to share a mutex between threads to share a queue. I have a messenger class that will be sending the messages and in the header I declared my constructor like so:

class Messenger {
public:
    Messenger(std::mutex& m);
    Messenger();
    std::mutex& mutex;

private:   
    //variables
    zmq::context_t zmq_context;
    zmq::socket_t zmq_socket;
};

and the corresponding c++ is

/**
 * Blank constructor
 */
Messenger::Messenger(){

}

Messenger::Messenger(std::mutex& m) : 
zmq_context(1),
zmq_socket(zmq_context, ZMQ_PUB),
mutex(m)
{

}

Then in my main application code I give it the mutex and instantiate it like so:

//start code
std::mutex mutex;
auto msgr = std::make_unique<Messenger>(std::ref(mutex));

This will compile but throws a linker error complaining about an undefined reference to `Messenger::Messenger(std::mutex&)'

/usr/bin/ld: CMakeFiles/ImuStream.dir/imu_stream.cpp.o: in function `std::_MakeUniq<Messenger>::__single_object std::make_unique<Messenger, std::reference_wrapper<std::mutex> >(std::reference_wrapper<std::mutex>&&)':
imu_stream.cpp:(.text._ZSt11make_uniqueI9MessengerJSt17reference_wrapperISt5mutexEEENSt9_MakeUniqIT_E15__single_objectEDpOT0_[_ZSt11make_uniqueI9MessengerJSt17reference_wrapperISt5mutexEEENSt9_MakeUniqIT_E15__single_objectEDpOT0_]+0x41): undefined reference to `Messenger::Messenger(std::mutex&)'
collect2: error: ld returned 1 exit status

However if I change the declaration to this:

class Messenger {
    public:
        //Messenger(std::mutex& m);
        Messenger(std::mutex& m) : mutex(m) {};
        Messenger();
        std::mutex& mutex;
    
    private:   
        //variables
        zmq::context_t zmq_context;
        zmq::socket_t zmq_socket;
    };

Then it links just fine. Why is that? And why isn't the linker mad that I did not put zmq_context or zmq_socket in the class definition?

Thank you.

---adding compiling method---- I'm using cmake to compile, this is my cmake file:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(ImuStream VERSION 1.0)

#configure header for setting the version
configure_file(ImuStreamConfig.h.in ImuStreamConfig.h)

# add the executable
add_executable(ImuStream imu_stream.cpp)

#find cppzmq wrapper, installed by make of cppzmq
find_package(cppzmq)


target_link_libraries(ImuStream  cppzmq)

target_include_directories(ImuStream PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

I just make a build folder, do a cmake .. and then a make. Looks like I forgot to add Messenger.cpp to my cmake file :(

confused
  • 713
  • 1
  • 5
  • 16
  • 1
    You are not compiling and/or linking the `.cpp` file with the `Messenger` constructor implementation. – user17732522 Jun 16 '22 at 17:52
  • 1
    Also "_And why isn't the linker mad that I did not put zmq_context or zmq_socket in the class definition?_": That has nothing to do with the linker. If at all that would be a concern in the compilation stage, not the linking stage. But you are allowed to not specify initializers for members. You don't do this in the default constructor `Messenger::Messenger()` either. What will happen in that case depends on what kind of type `zmq::context_t` and `zmq::socket_t` are. – user17732522 Jun 16 '22 at 17:55
  • 1
    For further help, you would need to at least add information about how exactly you are compiling (and linking) the relevant files. – user17732522 Jun 16 '22 at 17:58
  • 1
    Damn I hate that duplicate. Your answer is in there somewhere, but good luck finding it or recognizing that you found it. With more information in the question we can point you at the specific case you've run into. – user4581301 Jun 16 '22 at 18:04
  • @user17732522 that was it, I forgot to add Messenger.cpp in my cmake file. I don't know why I did not think to look there. Now it throws a Messenger.cpp:6:1: error: uninitialized reference member in ‘class std::mutex&’ [-fpermissive] 6 | Messenger::Messenger(){ but that's another problem I guess. Thanks! – confused Jun 16 '22 at 18:29
  • 1
    @confused I should have mentioned that anyway in my previous comment, but that new error is because while you can leave members generally without initializer in a constructor, that applies only if the member can be default-initialized, which references can't. So leaving out the initializer for `zmq_context` and `zmq_socket` is actually fine, but it isn't ok to leave out an initializer for a reference member such as `mutex` which you are doing in the default constructor. Usually it doesn't make sense to have a default constructor if you have a reference member. – user17732522 Jun 16 '22 at 18:31
  • @user17732522 thank you, removing the constructor fixed. Thank you for the help this saved me a ton of time this afternoon :) – confused Jun 16 '22 at 18:37

0 Answers0