Is it possible to defer member initialization to the constructor body?

后端 未结 8 604
一生所求
一生所求 2021-01-13 14:25

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\'

相关标签:
8条回答
  • 2021-01-13 14:35

    I think that's one possible use case for boost::optional.

    0 讨论(0)
  • 2021-01-13 14:36

    I think your solution is the correct way to do things.

    You can also postpone the creation of the object by making is pointer (however it changes the code and data type):

    std::auto_ptr<udp::socket> _sock;
    

    And then in body:

    _sock.reset(new udp::soket(_io_service, ep));
    

    But I think that your "workaround" is rather correct solution then workaround.

    0 讨论(0)
  • 2021-01-13 14:40

    When you define a constructor, you have 2 ways to "initialize" attributes:

    • the initializer list
    • the constructor body

    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.

    0 讨论(0)
  • 2021-01-13 14:41

    You could turn the _sock member into a smart pointer:

    #include <boost/asio.hpp>
    #include <boost/array.hpp>
    #include <boost/scoped_ptr.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;
            boost::scoped_ptr<udp::socket> _sock_ptr;
            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_ptr.reset(new udp::socket(_io_service, ep));
    }
    
    0 讨论(0)
  • 2021-01-13 14:43

    In C++ it's preferable to initialize members in the initializer list, rather than the body of the constructor, so in fact you might consider putting other members in the initialization list

    If you're thinking about creating a constructor that other ctors call, that's not available til c++0x (see inheriting constructors)

    0 讨论(0)
  • 2021-01-13 14:43

    Another option in this case is to work around the issue by creating a static function to build ep:

    #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:
            static udp::endpoint build_ep(const std::string &host,
              unsigned short port, boost::asio::io_service &io_service);
    
            boost::asio::io_service _io_service;
            udp::socket _sock;
            boost::array<T,256> _buf;
    };
    
    template<class T>
    udp::endpoint udp_sock<T>::build_ep(const std::string &host,
      unsigned short port, boost::asio::io_service &io_service)
    {
        udp::resolver res(io_service);
        udp::resolver::query query(udp::v4(), host, "spec");
        udp::endpoint ep = *res.resolve(query);
        ep.port(port);
        return ep;
    }
    
    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost",
      unsigned short port = 50000)
        : _sock(_io_service, build_ep(host, port, _io_service))
    {
    }
    
    0 讨论(0)
提交回复
热议问题