2

I am trying to make a class that manipulates with Boost sockets to make the conections simple to use.
My SocketClient class has a few properties with boost::asio::ip::tcp::socket being one of them. But I get C2512 error in my constructor, because boost::asio::ip::tcp::socket cannot exist unitialised, as it has no constructor.
Here, see the code of the class:

class SocketClient {
private:
    int port;    //Port, currently unused
    boost::asio::io_service io_service;  
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator;  
    boost::asio::ip::tcp::socket sock;  //This causes the error
    //It wants to be like this (impossible too):
  //boost::asio::ip::tcp::socket sock(io_service);
public:
    void init(const char*, const char* );
    SocketClient();  //Default constructor
    bool connect();
    bool read(int bytes, char *text);
    bool send(int length, char *text);
    bool send(std::string text);
    unsigned int timeout;
};

And here is the constructor:

SocketClient::SocketClient() {  //ERROR: (23): error C2512: 'boost::asio::basic_stream_socket<Protocol>' : no appropriate default constructor available
    sock=boost::asio::ip::tcp::socket(io_service);  //Adding this didn't help
}

So what to do? Do I have to keep sock as void*?

Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • possible duplicate of [Avoid default constructor for member variable](http://stackoverflow.com/questions/15420547/avoid-default-constructor-for-member-variable) – David G Mar 14 '13 at 21:36
  • 1
    I find [this question](http://stackoverflow.com/questions/15420547/avoid-default-constructor-for-member-variable), posed just six minutes prior to this one, strikingly similar. – chris Mar 14 '13 at 21:36
  • You are right, but note that six minutes it takes to write the question, and google indexes a bit slower. – Tomáš Zato Mar 14 '13 at 21:43

4 Answers4

5

Use initialization lists:

SocketClient::SocketClient() 
    :
    sock(io_service)
{
    // Other initialization code here...
}

Be careful though: this is well-defined because member variables are constructed in the order they appear in the class definition, and io_service appears before sock. If that wasn't the case, you would pass an uninitialized object to the constructor of socket, most likely resulting in Undefined Behavior.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Could you explain it more? – Tomáš Zato Mar 14 '13 at 21:35
  • @TomášZato, http://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor – chris Mar 14 '13 at 21:37
  • I just noticed that using your trick, I can not define default constructor any more... – Tomáš Zato Mar 14 '13 at 21:51
  • @TomášZato: What do you mean? Initialization lists don't prevent you from defining a default constructor. In fact, that's what I defined. – Andy Prowl Mar 14 '13 at 21:51
  • When I try to define `SocketClient::SocketClient()` I get **redefinition error** - and I am warned that I am redefining the constructor defined by your code. Isn't there anything I should add to it? – Tomáš Zato Mar 14 '13 at 21:59
  • @TomášZato: My definition above *is* the definition of the default constructor. Why do you want to define two default constructors? Of course you can't do that – Andy Prowl Mar 14 '13 at 22:00
  • Maybe I want another things to happen, when class is defined, not only initialise `socket`. – Tomáš Zato Mar 14 '13 at 22:04
  • @TomášZato: Then add those things in the body of the constructor, as you would normally do. The constructor body in my example is empty because the constructor body in *your* example did nothing else than initializing `sock`, but you are free to change it – Andy Prowl Mar 14 '13 at 22:05
0

If you are using C++ 11, you can do it like this:

boost::asio::io_service io_service;  
boost::asio::ip::tcp::resolver::iterator endpoint_iterator;  
boost::asio::ip::tcp::socket sock { io_service };

But (as Andy Prowl said) io_service must be must be placed before sock in the member list.

This would compile, but may lead to unpredictable errors:

boost::asio::ip::tcp::socket sock { io_service };
boost::asio::io_service io_service;
DirkMausF
  • 715
  • 5
  • 14
0

generally - as already stated - whenever possible use initialization lists. also use a naming scheme that identifies members.

also already stated - initialization depends on member order. if you have dependencies between members this is most often a sign for a design error. it smells. at least document this well in the code - there is always a next maintainer. of course you can alway hold elements via typed (smart) pointers.

for the concrete problem I'd suggest to pass the io_service via reference. this would give you more control over the io_service (eg. use async mode and run multiple sockets within one io_service)

#include <boost/asio.hpp>

class SocketClient {
private:
    boost::asio::io_service& m_io_service;
    boost::asio::ip::tcp::socket m_socket;

[...]

public:
    SocketClient(boost::asio::io_service& io_service);

[...]

};


SocketClient::SocketClient(boost::asio::io_service& io_service)
    : m_io_service(io_service)
    , m_socket(io_service)
    [...]
{
}
stefan
  • 3,681
  • 15
  • 25
0

header .h

boost::asio::ip::tcp::socket *sock;

body .cpp

sock = new boost::asio::ip::tcp::socket(service);
sitev_ru
  • 23
  • 1
  • 4