0

I've encountered a problem when creating a client class for a program I'm doing.

I have the class defined in the header, like so:

class Client {
public:
    Client();

private:
    tcp::socket socket;
    boost::asio::io_context io_context;
    tcp::resolver resolver;
    tcp::resolver::results_type endpoints;
};

However, when constructing the class, the program crashes with an error related to the socket initialization.

Here's the class constructor:

Client::Client() : resolver(io_context), endpoints(resolver.resolve("localhost", "daytime")), socket(io_context) { // Error here.
    try {
        boost::asio::connect(socket, endpoints);
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

The call stack goes from the client class, to basic_socket and some other boost classes, until going to win_mutex, where the program finally crashes with an overflow error.

Is there something I'm doing wrong?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
AlexINF
  • 250
  • 2
  • 11
  • what you mean about `overflow error` ? to do that in a constructor is 'dangerous' you can have calls to the constructor for temporary instances etc made implicitly by the compiler even you don't have explicitly put in code – bruno Jan 11 '19 at 20:58
  • 3
    Note that class members are initialised in the order in which they are declared within the class definition. The order in which they appear in the constructor's initialisation list is irrelevant. See [here for example](https://en.cppreference.com/w/cpp/language/initializer_list#Initialization_order). So you are actually initialising `socket` *before* `io_context` has been initialised. – G.M. Jan 11 '19 at 20:59
  • And how do I initialize io_context first then? – AlexINF Jan 11 '19 at 21:02
  • 1
    @AlexINF G.M`s comment is answer to your problem. io_context must exist before socket is created. Declare io_context before socket in your class. – rafix07 Jan 11 '19 at 21:02
  • I'm trying to set `io_context` to the default constructor `boost::asio::io_context()` in the client header, however, it still doesn't work. Am I missing something? Sorry. – AlexINF Jan 11 '19 at 21:06
  • 1
    @AlexINF In the `private` section of your class definition put `boost::asio::io_context io_context` first -- before `socket`, `resolver` etc. This is probably a dupe of [`"C++: Initialization Order of Class Data Members "`](https://stackoverflow.com/questions/2669888/c-initialization-order-of-class-data-members). – G.M. Jan 11 '19 at 21:12
  • 1
    Ohh! I see! I thought you were talking about the order of the initializing in the constructor. It works now though! Thanks! Please leave an answer so I can properly mark it as answered. – AlexINF Jan 11 '19 at 21:15
  • 3
    If your compiler didn't give you a warning about initialization order, you should either switch to a better compiler or learn how to enable warnings in your compiler. – David Schwartz Jan 11 '19 at 21:34
  • Just enabled the /WX feature in Visual Studio. Thanks for the tip! – AlexINF Jan 11 '19 at 21:45

1 Answers1

0

(Answered myself since nobody from the comments did in two days, thanks to G.M for all the help)

The problem is in the order of initialization of the variables. Having socket declared before anything else causes problems.

To fix, I just had to change this:

class Client {
    public:
        Client();

    private:
        tcp::socket socket;
        boost::asio::io_context io_context;
        tcp::resolver resolver;
        tcp::resolver::results_type endpoints;
};

To this:

class Client {
    public:
        Client();

    private:
        boost::asio::io_context io_context;
        tcp::resolver resolver;
        tcp::resolver::results_type endpoints;
        tcp::socket socket; // Note the order of the variable declaration
};
AlexINF
  • 250
  • 2
  • 11