I have a class with an object as a member which doesn't have a default constructor. I'd like to initialize this member in the constructor, but it seems that in C++ I can't do that. Here is the class:
#include <boost/asio.hpp>
#include <boost/array.hpp>
using boost::asio::ip::udp;
template<class T>
class udp_sock
{
public:
udp_sock(std::string host, unsigned short port);
private:
boost::asio::io_service _io_service;
udp::socket _sock;
boost::array<T,256> _buf;
};
template<class T>
udp_sock<T>::udp_sock(std::string host = "localhost",
unsigned short port = 50000)
{
udp::resolver res(_io_service);
udp::resolver::query query(udp::v4(), host, "spec");
udp::endpoint ep = *res.resolve(query);
ep.port(port);
_sock(_io_service, ep);
}
The compiler tells me basically that it can't find a default constructor for udp::socket and by my research I understood that C++ implicitly initializes every member before calling the constructor. Is there any way to do it the way I wanted to do it, or is it too "Java-oriented" and not feasible in C++?
I worked around the problem by defining my constructor like this:
template<class T>
udp_sock<T>::udp_sock(std::string host = "localhost",
unsigned short port = 50000) : _sock(_io_service)
{
udp::resolver res(_io_service);
udp::resolver::query query(udp::v4(), host, "spec");
udp::endpoint ep = *res.resolve(query);
ep.port(port);
_sock.bind(ep);
}
So my question is more out of curiosity and to better understand OOP in C++
When you define a constructor, you have 2 ways to "initialize" attributes:
If you do not explictly initialize one of the attributes in the initializer list, it is nonetheless initialized (by calling its default constructor) for you...
So in essence:
class Example
{
public:
Example();
private:
Bar mAttr;
};
// You write
Example::Example() {}
// The compiler understands
Example::Example(): mAttr() {}
And this of course fails if the underlying type does not have a Default Constructor.
There are various ways to defer this initialization. The "standard" way would be to use a pointer:
class Example { public: Example(); private: Bar* mAttr; };
However I prefer using Boost.Optional combined with suitable accessors:
class Example
{
public: Example();
private:
Bar& accessAttr() { return *mAttr; }
const Bar& getAttr() const { return *mAttr; }
boost::Optional<Bar> mAttr;
};
Example::Example() { mAttr = Bar(42); }
Because Boost.Optional means that there is no overhead on the allocation and no overhead on the dereferencing (the object is created in place) and yet carries the correct semantic.