简体   繁体   中英

Make a class with no default constructor a private property of another class

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* ?

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.

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;

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)
    [...]
{
}

header .h

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

body .cpp

sock = new boost::asio::ip::tcp::socket(service);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM