2010-03-17 16 views
3

我有一个对象作为没有默认构造函数的成员的类。我想在构造函数中初始化这个成员,但似乎在C++中我无法做到这一点。这里是类:是否有可能将成员初始化推迟到构造函数体?

#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); 
} 

编译器告诉我,基本上,它找不到UDP ::插座一个默认的构造,并通过我的研究,我了解C++隐式调用构造函数之前,每一个成员初始化。有没有办法以我想要的方式去做,或者它是否太“面向Java”,在C++中不可行?

我工作围绕这一问题通过定义这样我的构造函数:

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); 
} 

所以我的问题是更多的是出于好奇和更好地理解面向对象的C++

+0

或者您可以驱逐在外面的功能在体内产生的计算:'udp_sock ():_sock(myfunc()){}' – 2010-03-17 17:29:25

回答

8

当你定义一个构造函数,你有2种方式 “初始化” 属性:

  • 初始化列表
  • 的构造体

如果你没有exp在初始化器列表中初始化其中一个属性,然后初始化它(通过调用它的默认构造器)给你...

因此,在本质:

class Example 
{ 
public: 
    Example(); 
private: 
    Bar mAttr; 
}; 

// You write 
Example::Example() {} 

// The compiler understands 
Example::Example(): mAttr() {} 

这当然如果基础类型不具有默认构造函数失败。

推迟初始化有多种方法。的“标准”方法是使用一个指针:

class Example { public: Example(); private: Bar* mAttr; }; 

但是我更喜欢使用Boost.Optional结合合适的存取:

class Example 
{ 
public: Example(); 
private: 
    Bar& accessAttr() { return *mAttr; } 
    const Bar& getAttr() const { return *mAttr; } 
    boost::Optional<Bar> mAttr; 
}; 

Example::Example() { mAttr = Bar(42); } 

因为Boost.Optional意味着有该分配没有开销和在解引用(对象创建就位)上没有任何开销,但却带有正确的语义。

+0

感谢您使用boost :: optional的快速​​示例,它为我节省了阅读文档所需的时间,以了解它是否可以帮助我或不。这正是我想到的! – Kjir 2010-03-17 17:44:54

+0

当你找到一段时间时,不要犹豫,阅读它。它实际上很短,因为它是一个简单的实用程序,但有一些选项(如就地工厂来构建对象)值得检查。 – 2010-03-18 07:16:47

1

我认为这是一个可能的使用案例boost::optional

+0

在写我的例子的时候打我:p这是我处理这种情况的首选方法。 – 2010-03-17 17:26:25

+0

这是我寻找的解决方案,但我选择Matthieu的答案,因为他还提供了一个简单的用例。 – Kjir 2010-03-17 17:49:04

0

在C++中,它是最好初始化成员初始化列表,而不是在构造函数体,所以实际上你可能会考虑把其他成员在初始化列表

如果你想创建一个构造其他构建函数调用,这是不可直到的C++ 0x(见inheriting constructors

0

如果它的初始化施工过程中的变量在类的构造函数的正确方法是:

template<class T> 
udp_sock<T>::udp_sock(std::string host = "localhost", unsigned short port = 50000) 
    :res(_io_service) 
    ,query(udp::v4(), host, "spec") 
    ,ep(*res.resolve(query)) 
    ,_sock(_io_service, ep) 
{ 
} 

艾迪t:忘了提及'res','query'和'ep'应该是班级的一部分。另一种粗略的方法(没有_sock作为指针)如下:

template<class T> 
udp_sock<T>::udp_sock(std::string host = "localhost", unsigned short port = 50000) 
    :_sock(_io_service, udp::resolver(_io_service).resolve(udp::resolver::query(udp::v4(),host,"spec")) 
{ 
} 
+0

但是这需要制作res,query和ep类成员而不是构造函数的局部变量,这会改变他的类的内容,并且不是特别优雅。 – 2010-03-17 17:28:30

+0

我忘记提及了。我已经添加到编辑中,并添加了另一个构造函数,它不需要任何这些变量作为成员变量。它们在运行时创建,一旦使用就会被销毁。使用此方法的主要缺点是在施工期间发生的异常会导致内存泄漏。最好的方法是使用_sock作为指针或boost :: scoped_ptr。 – 2010-03-17 17:33:57

+0

我自己想过第二个版本,但是我发现它没有我想要的那么优雅,所以我一直在寻找更好的解决方案。 – Kjir 2010-03-17 17:40:08

0

我认为你的解决方案是正确的做事方式。

您也可以通过使推迟对象的创建指针(但是它改变了代码和数据类型):

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

然后在身体:

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

但我认为您的“解决方法”是相当正确的解决方案,然后解决方法。

+0

我打算建议一样的。但是,而不是std :: auto_ptr我会建议boost :: scoped_ptr,因为他已经在使用boost库。 – 2010-03-17 17:25:31

+0

指针意味着堆使用开销和螺旋复制语义......尽管'scoped_ptr'至少会暴露复制问题! – 2010-03-17 17:28:02

+0

我只是希望尽可能使用标准库,特别是当'scoped_ptr'只是“一点点”剥离'auto_ptr'时。我从来没有用过。 – Artyom 2010-03-17 17:28:15

0

你可以打开_sock件冲进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

这意味着堆分配+复制语义问题。这是很多伤害。 – 2010-03-17 17:27:02

+0

与他的情况不同,因为'boost :: asio :: io_service'已经不可复制。 – 2010-03-17 17:30:41

+0

我也想过指针,但我想避免处理分配/释放以及与指针相关的所有潜在问题。我试图避免指针,除非它们是唯一的解决方案,或者它们提供了明确的速度优势... – Kjir 2010-03-17 17:41:53

0

在这种情况下,另一种选择是通过创建一个静态函数建立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)) 
{ 
} 
相关问题